thread_threadlocal - CSDN
thread 订阅
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。线程是独立调度和分派的基本单位。线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。一个进程可以有很多线程,每条线程并行执行不同的任务。在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。 展开全文
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。线程是独立调度和分派的基本单位。线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。一个进程可以有很多线程,每条线程并行执行不同的任务。在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。
信息
提出者
dozer
定    义
程序执行流的最小单元
多线程中
CPU的基本单位
应用学科
计算机
中文名
线程
外文名
thread
别    称
执行绪;轻量进程
线程发展简史
线程的引入:60年代,在OS中能拥有资源和独立运行的基本单位是进程,然而随着计算机技术的发展,进程出现了很多弊端,一是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销,因此需要引入轻型进程;二是由于对称多处理机(SMP)出现,可以满足多个运行单位,而多个进程并行开销过大。因此在80年代,出现了能独立运行的基本单位——线程(Threads)。
收起全文
精华内容
参与话题
  • JAVA核心知识点--Thread线程基础

    万次阅读 多人点赞 2019-03-27 17:53:38
    继承java.lang.Thread类 实现java.lang.Runnable接口 三、线程的状态 四、线程的基本方法和属性 五、线程资源共享示例 一、什么是线程? 线程是一个程序的多个执行路径,执行调度的单位,依托于进程而存在。 ...

    目录

    一、什么是线程?

    二、线程的创建

    继承java.lang.Thread类

    实现java.lang.Runnable接口

    三、线程的状态

    四、线程的基本方法和属性

    五、线程资源共享示例


    一、什么是线程?

    线程是一个程序的多个执行路径,执行调度的单位,依托于进程而存在。 线程不仅可以共享进程的内存,而且还拥有一个属于自己的内存空间,这段内存空间也叫做线程栈,是在建立线程时由系统分配的,主要用来保存线程内部所使用的数据,如线程执行函数中所定义的变量。

    注意:Java中的多线程是一种抢占机制而不是分时机制。抢占机制指的是有多个线程处于可运行状态,但是只允许一个线程在运行,他们通过竞争的方式抢占CPU。  

    二、线程的创建

    在Java中可以通过以下两种方式定义线程:

    • 继承java.lang.Thread类 。
    • 实现java.lang.Runnable接口。

    继承java.lang.Thread类

    /**
     * 通过继承java.lang.Thread类来定义线程
     */
    public class MyThread extends Thread {
    
    	private boolean flag = true;
    
    	public MyThread(String threadName) {
    		super(threadName);
    	}
    
    	@Override
    	public void run() {
    		while (flag) {
    			System.out.println(Thread.currentThread().getName()
    					+ " Is Running...");
    		}
    	}
    
    	public void shutDown() {
    		this.flag = false;
    	}
    
    	public static void main(String[] args) throws InterruptedException {
    		MyThread myThread = new MyThread("MyThread");
    		myThread.start();
    		Thread.sleep(1000);
    		myThread.shutDown();
    
    	}
    }
    

    实现java.lang.Runnable接口

    /**
     * 通过实现Runnable接口来定义线程
     */
    public class MyThread implements Runnable {
    	private boolean flag = true;
    
    	@Override
    	public void run() {
    		while (flag) {
    			System.out.println(Thread.currentThread().getName()
    					+ " Is Running...");
    		}
    	}
    
    	public void shutDown() {
    		this.flag = false;
    	}
    
    	public static void main(String[] args) throws InterruptedException {
    
    		MyThread myThread = new MyThread();
    		Thread thread = new Thread(myThread, "MyThread");
    		thread.start();
    		Thread.sleep(1000);
    		myThread.shutDown();
    
    	}
    }
    

    在线程的start()方法被调用后,JVM会自动调用线程的run()方法来执行任务。start()方法结束,线程也就终止了。

    注意:推荐使用实现Runnable接口的方式来定义线程,因为Java中的类只支持单继承,你一旦继承了Thread类就不能再继承其他的类了,会大大降低程序的可扩展性和灵活性。  

    三、线程的状态

    四、线程的基本方法和属性

    1)优先级(priority)

    每个线程都有一个优先级(用1-10的整数表示,默认优先级是5,高优先级线程的执行优先于低优先级线程。默认一个线程的优先级和创建他的线程优先级相同。

    以下是Thread定义的三个与优先级相关的静态常量: 

    MAX_PRIORITY =10
    NORM_PRIORITY =5
    MIN_PRIORITY=1

    2)Thread.sleep(long millis)/sleep(long millis)

    使当前线程休眠(暂停执行)millis毫秒的时间(millis指定的休眠时间是其最小的不执行时间,因为在sleep()休眠时间期满后,该线程不一定会立即执行,这是因为其它线程可能正在运行而且没有被调度为放弃执行,除非此线程具有更高的优先级);sleep()是Thread类的static(静态)的方法;因此他不能改变对象的机锁,所以当在一个Synchronized块中调用sleep()方法时,线程虽然休眠了,但是对象的机锁并没有被释放,其他线程无法访问这个对象(即使睡着也持有对象锁)。 

    作用:保持对象锁,让出CPU,调用目的是不让当前线程独自霸占该进程所获取的CPU资源,以留一定的执行机会给其他线程;

    3)Thread.yield()

    让出CPU的使用权,让其他同等优先级或更高优先级的线程可以获取到运行机会,线程yield()时也不会释放对象锁。

    sleep()和yield()的区别:

    • sleep()方法会给其他线程运行的机会,而不考虑其他线程的优先级,因此会给较低优先级线程一个运行的机会;yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。 
    • 当线程执行了sleep(long millis)方法后,将转到阻塞状态,参数millis指定休眠时间;当线程执行了yield()方法后,将转到就绪状态。 
    • sleep()方法声明抛出InterruptedException异常,而yield()方法没有声明抛出任何异常 。

    4)thread.join()

    线程合并,使用该方法的线程会在此线程执行完毕后才往下继续执行,可使异步线程变为同步线程。

    5)object.wait()

    wait()方法是Object类里的方法;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去机锁,wait(long timeout)超时时间到后还需要返还对象锁),其他线程可以访问。执行wait()方法的线程必须拥有当前对象的锁,如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常,所以wait()必须在synchronized block中调用。

    wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前等待池中的线程。

    6)object.notify()/notifyAll()

    唤醒在当前对象等待池中等待的一个线程/所有线程。notify()/notifyAll()也必须拥有相同对象锁,否则也会抛出IllegalMonitorStateException异常。

    7)Synchronized Block

    Java中的每一个对象都有唯一的一个内置的锁,每个Synchronized Block或同步的方法只有持有调用该方法被锁定对象的锁的线程才可以访问,否则所属线程阻塞;机锁具有独占性、一旦被一个Thread持有,其他的Thread就不能再拥有(不能访问其他同步方法),方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。

    五、线程资源共享示例

    /**
     * 车站售票示例
     */
    public class TicketsThread implements Runnable {
    
    	// 车票总数
    	private Integer tickets = 100;
    	private boolean flag = true;
    	private Object object = new Object();
    
    	@Override
    	public void run() {
    		while (flag) {
    			/*	synchronized (object) {
    				if (tickets > 0) {
    					try {
    						Thread.sleep(100);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println(Thread.currentThread().getName() + "售出第"
    							+ tickets + "张车票");
    					tickets--;
    				} else {
    					System.out.println(Thread.currentThread().getName()
    							+ "提醒广大乘客:车票已经售完,停止售票!");
    					this.flag = false;
    				}
    			}*/
    			sell();
    		}
    
    	}
    
    	private  synchronized void sell(){
    		if (tickets > 0) {
    			try {
    				Thread.sleep(100);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			System.out.println(Thread.currentThread().getName() + "售出第"
    					+ tickets + "张车票");
    			tickets--;
    		} else {
    			System.out.println(Thread.currentThread().getName()
    					+ "提醒广大乘客:车票已经售完,停止售票!");
    			this.flag = false;
    		}
    	}
    	
    	public void shutDown() {
    		this.flag = false;
    	}
    
    	public static void main(String[] args) {
    		TicketsThread ticketsThread = new TicketsThread();
    		Thread thread1 = new Thread(ticketsThread, "售票处1");
    		Thread thread2 = new Thread(ticketsThread, "售票处2");
    		Thread thread3 = new Thread(ticketsThread, "售票处3");
    
    		thread1.start();
    		thread2.start();
    		thread3.start();
    
    	}
    
    }
    /**
     * 死锁示例
     */
    public class DeadThread implements Runnable {
    
    	private Object obj1 = new Object();
    	private Object obj2 = new Object();
    
    	private boolean flag = true;
    
    	@Override
    	public void run() {
    		if (flag) {
    			synchronized (obj1) {
    				try {
    					Thread.sleep(500);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				synchronized (obj2) {
    
    				}
    			}
    		} else {
    			synchronized (obj2) {
    				try {
    					Thread.sleep(500);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				synchronized (obj1) {
    
    				}
    			}
    		}
    
    	}
    
    	public static void main(String[] args) throws InterruptedException {
    		DeadThread deadThread = new DeadThread();
    		Thread thread1 = new Thread(deadThread);
    		Thread thread2 = new Thread(deadThread);
    		thread1.start();
    		Thread.sleep(100);
    		deadThread.flag = false;
    		thread2.start();
    
    	}
    
    }

      

    展开全文
  • Thread详解

    千次阅读 2018-08-24 14:38:57
    1.1什么是线程?  线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被...

    1.1什么是线程? 

    线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。

      线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。

     1.2 什么是线程安全性?

    如果一个类可以安全地被多个线程使用,它就是线程安全的。你无法对此论述提出任何争议,但也无法从中得到更多有意义的帮助。那么我们如何辨别线程安全与非线程安全的类?我们甚至又该如何理解“安全”呢?任何一个合理的“线程安全性”定义,其关键在于“正确性”的概念。在<<JAVA并发编程实践>>书中作者是这样定义的:一个类是是线程安全的,是指在被多个线程访问时,类可以持续进行正确的行为。或当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用方代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类是线程安全的。

     1.3 线程的六种状态

    线程从创建到销毁期间有六种状态:

    • New: 至今尚未启动的线程的状态。 
    • Runnable :可运行线程的线程状态。
    • Blocked :受阻塞并且正在等待监视器锁的某一线程的线程状态。
    • Waiting :某一等待线程的线程状态。
    • Timed_waiting:具有指定等待时间的某一等待线程的线程状态。
    • Terminated:已终止线程的线程状态。线程已经结束执行。
    • 如下图所示:
    •  

     

     

     

    二、Thread类

       2.1 属性

    [java] view plain copy

    1. //线程名字,通过构造参数来指定  
    2. private char        name[];  
    3. //表示线程的优先级,优先级越高,越优先被执行(最大值为10,最小值为1,默认值为5)  
    4. private int         priority;  
    5.   
    6. private Thread      threadQ;  
    7. private long        eetop;  
    8.   
    9. /* Whether or not to single_step this thread. */  
    10. private boolean     single_step;  
    11.   
    12. //线程是否是守护线程:当所有非守护进程结束或死亡后,程序将停止   
    13. private boolean     daemon = false;  
    14.   
    15. /* JVM state */  
    16. private boolean     stillborn = false;  
    17.   
    18. //将要执行的任务  
    19. private Runnable target;  
    20.   
    21. /* 线程组表示一个线程的集合。此外,线程组也可以包含其他线程组。线程组构成一棵树,在树中,除了初始线程组外,每个线程组都有一个父线程组。  */  
    22. private ThreadGroup group;  
    23.   
    24. /* The context ClassLoader for this thread */  
    25. private ClassLoader contextClassLoader;  
    26.   
    27. /* The inherited AccessControlContext of this thread */  
    28. private AccessControlContext inheritedAccessControlContext;  
    29.   
    30. /*第几个线程,在init初始化线程的时候用来赋给thread.name */    
    31. private static int threadInitNumber;  
    32. private static synchronized int nextThreadNum() {  
    33.     return threadInitNumber++;  
    34. }  
    35.   
    36. /* ThreadLocal values pertaining to this thread. This map is maintained 
    37.  * by the ThreadLocal class. */  
    38. ThreadLocal.ThreadLocalMap threadLocals = null;  
    39.   
    40. /* 
    41.  * InheritableThreadLocal values pertaining to this thread. This map is 
    42.  * maintained by the InheritableThreadLocal class. 
    43.  */  
    44. ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;  
    45.   
    46. /* 
    47.  * The requested stack size for this thread, or 0 if the creator did 
    48.  * not specify a stack size.  It is up to the VM to do whatever it 
    49.  * likes with this number; some VMs will ignore it. 
    50.  */  
    51. private long stackSize;  
    52.   
    53. /* 
    54.  * JVM-private state that persists after native thread termination. 
    55.  */  
    56. private long nativeParkEventPointer;  
    57.   
    58. /* 
    59.  * Thread ID 
    60.  */  
    61. private long tid;  
    62.   
    63. /* For generating thread ID */  
    64. private static long threadSeqNumber;  
    65.   
    66. /* 
    67.  *线程从创建到最终的消亡,要经历若干个状态。 
    68.  *一般来说,线程包括以下这几个状态:创建(new)、就绪(runnable)、运行(running)、阻塞(blocked)、time waiting、waiting、消亡(dead)。 
    69.  *  
    70.  */  
    71. private volatile int threadStatus = 0;  

       2.3 start()操作

    [java] view plain copy

    1. //启动新创建的线程  
    2. public synchronized void start() {  
    3.     /** 
    4.      * This method is not invoked for the main method thread or "system" 
    5.      * group threads created/set up by the VM. Any new functionality added 
    6.      * to this method in the future may have to also be added to the VM. 
    7.      * 
    8.      * A zero status value corresponds to state "NEW". 
    9.      */  
    10.     /*这个方法不会被主线程调用或通过虚拟机系统线程组创建起来。未来任何添加到该方法里的新功能可能需要加入到虚拟机中 
    11.      *  
    12.      * 状态new的值是0. 
    13.      * */  
    14.     if (threadStatus != 0)  
    15.         throw new IllegalThreadStateException();  
    16.   
    17.     /* Notify the group that this thread is about to be started 
    18.      * so that it can be added to the group's list of threads 
    19.      * and the group's unstarted count can be decremented. */  
    20.     /* 通知线程组新线程将要启动,以便它可以添加到线程组列表并且线程组没有开始计数*/  
    21.     group.add(this);  
    22.   
    23.     boolean started = false;  
    24.     try {  
    25.         start0();  
    26.         started = true;  
    27.     } finally {  
    28.         try {  
    29.             if (!started) {  
    30.                 group.threadStartFailed(this);  
    31.             }  
    32.         } catch (Throwable ignore) {  
    33.             /* do nothing. If start0 threw a Throwable then 
    34.               it will be passed up the call stack */  
    35.         }  
    36.     }  
    37. }  

       2.3 run()操作

    [java] view plain copy

    1. public void run() {  
    2.        if (target != null) {  
    3.             target.run();  
    4.        }  
    5.  }  

       2.4 start()和run()之间有什么区别?

       2.4.1 代码示例:run()方法使用

     

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. /** 
    4.  *  
    5.  * @author liulongling 
    6.  * 
    7.  */  
    8. public class ThreadTest extends Thread{  
    9.   
    10.     public ThreadTest(String name) {  
    11.         super.setName(name);  
    12.     }  
    13.   
    14.     @Override  
    15.     public void run() {  
    16.         for(int i = 0; i < 5;i++)  
    17.         {  
    18.             System.out.println(super.getName()+":"+i);  
    19.         }  
    20.     }  
    21.   
    22.     public static void main(String[] args) {  
    23.         ThreadTest test = new ThreadTest("A");  
    24.         ThreadTest test1 = new ThreadTest("B");  
    25.           
    26.         test.run();  
    27.         test1.run();  
    28.           
    29.         if(Thread.activeCount()>=1)  
    30.         {  
    31.             Thread.yield();  
    32.         }  
    33.     }  
    34. }  
    控制台:
    +------------------------------------------------------------------+
    

    A:0 A:1 A:2 A:3 A:4 B:0 B:1 B:2 B:3 B:4

    +------------------------------------------------------------------+

       2.4.2 代码示例:start()方法使用

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. /** 
    4.  *  
    5.  * @author liulongling 
    6.  * 
    7.  */  
    8. public class ThreadTest extends Thread{  
    9.   
    10.     public ThreadTest(String name) {  
    11.         super.setName(name);  
    12.     }  
    13.   
    14.     @Override  
    15.     public void run() {  
    16.         for(int i = 0; i < 5;i++)  
    17.         {  
    18.             System.out.println(super.getName()+":"+i);  
    19.         }  
    20.     }  
    21.   
    22.     public static void main(String[] args) {  
    23.         ThreadTest test = new ThreadTest("A");  
    24.         ThreadTest test1 = new ThreadTest("B");  
    25.           
    26.         test.start();  
    27.         test1.start();  
    28.           
    29.         if(Thread.activeCount()>=1)  
    30.         {  
    31.             Thread.yield();  
    32.         }  
    33.     }  
    34. }  
    控制台:
    +------------------------------------------------------------------+
    

    B:0 A:0 B:1 A:1 B:2 A:2 B:3 A:3 B:4 A:4

    +------------------------------------------------------------------+

       2.4.3 结果分析

       以上结果可以发现run()和单线程一样每次只能执行一个线程,而start()不一样有多个线程交叉执行着。我们知道start()方法被用来启动新创建的线程,而且start()内部通过本地系统调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法会启动新的线程,其中多个线程在CPU中是支持并发执行的。那么有没有什么方法可以让A线程优先执行呢?

     

       2.5 setPriority()操作

     

     

    [java] view plain copy

    1. public final void setPriority(int newPriority) {  
    2.        ThreadGroup g;  
    3.        checkAccess();  
    4.        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {  
    5.            throw new IllegalArgumentException();  
    6.        }  
    7.        if((g = getThreadGroup()) != null) {  
    8.            if (newPriority > g.getMaxPriority()) {  
    9.                newPriority = g.getMaxPriority();  
    10.            }  
    11.            setPriority0(priority = newPriority);  
    12.        }  
    13.    }  

    [java] view plain copy

    1. private native void setPriority0(int newPriority);  

     

       setPriority使用了native关键字,在Java API中,一个native方法意味着这个方法没有使用Java语言实现,只能通过代码示例去分析它的原理。在代码中将线程A的执行优先级设置为最高,同时线程B的优先级设置为最低,那么预期的结果应该是线程A先执行完后再执行线程B,代码如下:

     

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. /** 
    4.  *  
    5.  * @author liulongling 
    6.  * 
    7.  */  
    8. public class ThreadTest extends Thread{  
    9.   
    10.     public ThreadTest(String name) {  
    11.         super.setName(name);  
    12.     }  
    13.   
    14.     @Override  
    15.     public void run() {  
    16.         for(int i = 0; i < 5;i++)  
    17.         {  
    18.             System.out.println(super.getName()+":"+i);  
    19.         }  
    20.     }  
    21.   
    22.     public static void main(String[] args) {  
    23.         ThreadTest test = new ThreadTest("A");  
    24.         ThreadTest test1 = new ThreadTest("B");  
    25.         //MAX_PRIORITY是最高优先级  
    26.         test.setPriority(MAX_PRIORITY);  
    27.           
    28.         test.setPriority(MIN_PRIORITY);  
    29.         test.start();  
    30.         test1.start();  
    31.           
    32.         if(Thread.activeCount()>=1)  
    33.         {  
    34.             Thread.yield();  
    35.         }  
    36.     }  
    37. }  
    控制台:
    +------------------------------------------------------------------+
    A:0
    A:1
    A:2
    A:3
    A:4
    B:0
    B:1
    B:2
    B:3
    B:4
    +------------------------------------------------------------------+

       2.5 sleep(long millis)操作

     

    [java] view plain copy

    1. public static native void sleep(long millis) throws InterruptedException;  

     

      sleep也是使用了native关键字,调用了底层方法。sleep是指线程被调用时,占着CPU不工作,形象地说明为“占着CPU睡觉”,此时,系统的CPU部分资源被占用,其他线程无法进入。多线程下使用时需要注意的是sleep方法不会释放锁。比如:线程A和线程B执行一段加锁代码,线程A先进去,线程B在外面等待,其中代码程序有sleep方法让线程休眠,休眠后锁并不会被释放,线程B也只能继续在外面等待直到休眠时间结束。代码如下:

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. /** 
    6.  *  
    7.  * @author liulongling 
    8.  * 
    9.  */  
    10. public class ThreadTest{  
    11.   
    12.     private int i = 10;  
    13.     private Object object = new Object();  
    14.       
    15.     MyThread thread1 = new MyThread("A");  
    16.     MyThread thread2 = new MyThread("B");  
    17.        
    18.     public static void main(String[] args) throws IOException  {  
    19.         ThreadTest test = new ThreadTest();  
    20.         test.thread1.start();  
    21.         test.thread2.start();  
    22.     }   
    23.        
    24.        
    25.     class MyThread extends Thread{  
    26.         public MyThread(String name) {  
    27.             super.setName(name);  
    28.         }  
    29.         @Override  
    30.         public void run() {  
    31.             synchronized (object) {  
    32.                 System.out.println(Thread.currentThread().getName()+":"+i++);  
    33.                 try {  
    34.                     System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");  
    35.                     Thread.currentThread().sleep(1000);  
    36.                 } catch (InterruptedException e) {  
    37.                     // TODO: handle exception  
    38.                 }  
    39.                 System.out.println("线程"+Thread.currentThread().getName()+"被唤醒");  
    40.                 System.out.println(Thread.currentThread().getName()+":"+i);  
    41.             }  
    42.         }  
    43.     }  
    44. }  

     

    控制台:
    +------------------------------------------------------------------+
    

     

    A:10

    线程A进入睡眠状态

    线程A被唤醒

    A:11

    B:11

    线程B进入睡眠状态

    线程B被唤醒

    B:12

    +------------------------------------------------------------------+

       2.6 yield()操作

     

       调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。

     

     注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。

       2.7 isAlive()   

     

    [java] view plain copy

    1. /** 
    2.  * Tests if this thread is alive. A thread is alive if it has 
    3.  * been started and has not yet died. 
    4.  * 
    5.  * @return  <code>true</code> if this thread is alive; 
    6.  *          <code>false</code> otherwise. 
    7.  */  
    8. public final native boolean isAlive();  

      表示线程当前是否为可用状态,如果线程已经启动,并且当前没有任何异常的话,则返回true,否则为false

     

       2.8 join()操作

      join有3个重载方法:

     

       2.8.1 join() 

     

    [java] view plain copy

    1. //立即阻塞调用线程,直到该线程执行结束  
    2. public final synchronized void join(long millis)  
    3.         throws InterruptedException {  
    4.     long base = System.currentTimeMillis();  
    5.     long now = 0;  
    6.   
    7.     if (millis < 0) {  
    8.         throw new IllegalArgumentException("timeout value is negative");  
    9.     }  
    10.   
    11.     if (millis == 0) {  
    12.         //线程状态正常  
    13.         while (isAlive()) {  
    14.             wait(0);  
    15.         }  
    16.     } else {  
    17.         while (isAlive()) {  
    18.             long delay = millis - now;  
    19.             if (delay <= 0) {  
    20.                 break;  
    21.             }  
    22.             wait(delay);  
    23.             now = System.currentTimeMillis() - base;  
    24.         }  
    25.     }  
    26. }  

     

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. /** 
    6.  *  
    7.  * @author liulongling 
    8.  * 
    9.  */  
    10. public class ThreadTest{  
    11.   
    12.     private int i = 10;  
    13.     private Object object = new Object();  
    14.   
    15.     MyThread thread1 = new MyThread("A");  
    16.     MyThread thread2 = new MyThread("B");  
    17.   
    18.     public static void main(String[] args) throws IOException  {  
    19.         ThreadTest test = new ThreadTest();  
    20.         test.thread1.start();  
    21.         System.out.println("线程"+Thread.currentThread().getName()+"等待");  
    22.         try {  
    23.             test.thread1.join();  
    24.         } catch (InterruptedException e) {  
    25.             // TODO Auto-generated catch block  
    26.             e.printStackTrace();  
    27.         }  
    28.         System.out.println("线程"+Thread.currentThread().getName()+"执行");  
    29.         for (int j = 0; j < 5; j++)  
    30.         {  
    31.             System.out.println(Thread.currentThread().getName() + ":" + j);  
    32.         }  
    33.     }   
    34.   
    35.   
    36.     class MyThread extends Thread{  
    37.         public MyThread(String name) {  
    38.             super.setName(name);  
    39.         }  
    40.         @Override  
    41.         public void run() {  
    42.             synchronized (object) {  
    43.                 System.out.println(Thread.currentThread().getName()+":"+i++);  
    44.                 try {  
    45.                     System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");  
    46.                     Thread.currentThread().sleep(1000);  
    47.                 } catch (InterruptedException e) {  
    48.                     // TODO: handle exception  
    49.                 }  
    50.                 System.out.println("线程"+Thread.currentThread().getName()+"被唤醒");  
    51.                 System.out.println(Thread.currentThread().getName()+":"+i);  
    52.             }  
    53.         }  
    54.     }  
    55. }  
    控制台:
    +------------------------------------------------------------------+
    

     

    线程main等待

    A:10

    线程A进入睡眠状态

    线程A被唤醒

    A:11

    线程main执行

    main:0

    main:1

    main:2

    main:3

    main:4

     

      MSDN上解释join无参方法其作用为:阻塞 “调用线程” 直到某个线程结束。从上面结果可以分析出,A线程其实在main线程上运行,我们可以说main线程调用了A线程或称main线程为“调用线程”,A线程调用join()方法后将调用线程阻塞直到A线程结束后控制台才输出来main:0...。我们去掉join方法看下控制台输出结果。

     

    控制台:
    +------------------------------------------------------------------+

     

     

    main:0

    main:1

    A:10

    main:2

    线程A进入睡眠状态

    main:3

    main:4

    线程A被唤醒

    A:11

    +------------------------------------------------------------------+

       2.8.2 join(long millis)

      join(long millis)的参数作用是指定“调用线程”的最大阻塞时间。代码如下:

     

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. /** 
    6.  *  
    7.  * @author liulongling 
    8.  * 
    9.  */  
    10. public class ThreadTest{  
    11.   
    12.     private int i = 10;  
    13.     private Object object = new Object();  
    14.   
    15.     MyThread thread1 = new MyThread("A");  
    16.     MyThread thread2 = new MyThread("B");  
    17.   
    18.     public static void main(String[] args) throws IOException  {  
    19.         ThreadTest test = new ThreadTest();  
    20.         test.thread1.start();  
    21.         System.out.println("线程"+Thread.currentThread().getName()+"等待");  
    22.         try {  
    23.             test.thread1.join(500);  
    24.         } catch (InterruptedException e) {  
    25.             // TODO Auto-generated catch block  
    26.             e.printStackTrace();  
    27.         }  
    28.         System.out.println("线程"+Thread.currentThread().getName()+"执行");  
    29.         for (int j = 0; j < 5; j++)  
    30.         {  
    31.             System.out.println(Thread.currentThread().getName() + ":" + j);  
    32.         }  
    33.     }   
    34.   
    35.   
    36.     class MyThread extends Thread{  
    37.         public MyThread(String name) {  
    38.             super.setName(name);  
    39.         }  
    40.         @Override  
    41.         public void run() {  
    42.             synchronized (object) {  
    43.                 System.out.println(Thread.currentThread().getName()+":"+i++);  
    44.                 try {  
    45.                     System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");  
    46.                     Thread.currentThread().sleep(1000);  
    47.                 } catch (InterruptedException e) {  
    48.                     // TODO: handle exception  
    49.                 }  
    50.                 System.out.println("线程"+Thread.currentThread().getName()+"被唤醒");  
    51.                 System.out.println(Thread.currentThread().getName()+":"+i);  
    52.             }  
    53.         }  
    54.     }  
    55. }  

     

    
     

     

    线程main等待

    A:10

    线程A进入睡眠状态

    线程main执行

    main:0

    main:1

    main:2

    main:3

    main:4

    线程A被唤醒

    A:11

     

    +------------------------------------------------------------------+   从上面结果可以分析出,在A线程还未结束,主线程已经开始执行。原因是我们给主线程设置的阻塞时间是500ms,小于A线程run()方法里的1000ms休眠时间。

       2.8.3 join(long millis, int nanos)

      阻塞调用线程的时间最长为 millis 毫秒 + nanos 纳秒...这里就不举例说明了,原理和上一个方法一样。

     

     

     

       2.9 interrupt()操作

     

      interrupt的作用是中断正被阻塞的线程,比如我给某一线程休眠了10s时间,如果我在这个线程上调用了interrupt方法,看看会有什么效果。代码如下:

     

    [java] view plain copy

    1. package com.game.thread;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. /** 
    6.  *  
    7.  * @author liulongling 
    8.  * 
    9.  */  
    10. public class ThreadTest{  
    11.   
    12.     private int i = 10;  
    13.     private Object object = new Object();  
    14.   
    15.     MyThread thread1 = new MyThread("A");  
    16.     MyThread thread2 = new MyThread("B");  
    17.   
    18.     public static void main(String[] args) throws IOException  {  
    19.         ThreadTest test = new ThreadTest();  
    20.         test.thread1.start();  
    21.         test.thread1.interrupt();  
    22.     }   
    23.   
    24.   
    25.     class MyThread extends Thread{  
    26.         public MyThread(String name) {  
    27.             super.setName(name);  
    28.         }  
    29.         @Override  
    30.         public void run() {  
    31.             synchronized (object) {  
    32.                 System.out.println(Thread.currentThread().getName()+":"+i++);  
    33.                 try {  
    34.                     System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");  
    35.                     Thread.currentThread().sleep(10000);  
    36.                 } catch (InterruptedException e) {  
    37.                     System.out.println("你被中断了");  
    38.                 }  
    39.                 System.out.println("线程"+Thread.currentThread().getName()+"被唤醒");  
    40.                 System.out.println(Thread.currentThread().getName()+":"+i);  
    41.             }  
    42.         }  
    43.     }  
    44. }  
    控制台:
    +------------------------------------------------------------------+

     

    A:10

    线程A进入睡眠状态

    你被中断了

    线程A被唤醒

    A:11 +------------------------------------------------------------------+

     使用了 interrupt的结果是在休眠代码处抛出一个异常,并且阻塞马上停止了。

     

       3.0 setDaemon()操作

      用来设置线程是否成为守护线程和判断线程是否是守护线程。
      守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。Thread类有一个比较常用的静态方法currentThread()用来获取当前线程。

    展开全文
  • Thread

    千次阅读 2018-05-23 13:07:49
    1 start方法 start()用来启动一个线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要...注意,继承Thread类必须重写run方法,在run方法中定义具体要...

     1 start方法

      start()用来启动一个线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源。

      2 run方法

      run()方法是不需要用户来调用的,当通过start方法启动一个线程之后,当线程获得了CPU执行时间,便进入run方法体去执行具体的任务。注意,继承Thread类必须重写run方法,在run方法中定义具体要执行的任务。

    补充:用start()方法来启动线程,是真正实现了多线程,通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,无需等待run方法执行完毕,即可继续执行下面的代码。

    所以说:

    start()方法是真正实现了多线程run()方法只是一个普通的方法。

      3 sleep方法

      sleep方法有两个重载版本:

    1
    2
    3
    sleep(long millis)     //参数为毫秒
     
    sleep(long millis,int nanoseconds)    //第一参数为毫秒,第二个参数为纳秒
      
      sleep相当于让线程睡眠,交出CPU,让CPU去执行其他的任务。

         但是有一点要非常注意,sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。看下面这个例子就清楚了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    public class Test {
         
        private int i = 10;
        private Object object = new Object();
         
        public static void main(String[] args) throws IOException  {
            Test test = new Test();
            MyThread thread1 = test.new MyThread();
            MyThread thread2 = test.new MyThread();
            thread1.start();
            thread2.start();
        
         
         
        class MyThread extends Thread{
            @Override
            public void run() {
                synchronized (object) {
                    i++;
                    System.out.println("i:"+i);
                    try {
                        System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");  
                        Thread.currentThread().sleep(10000);
                    catch (InterruptedException e) {
                        // TODO: handle exception
                    }
                    System.out.println("线程"+Thread.currentThread().getName()+"睡眠结束");
                    i++;
                    System.out.println("i:"+i);
                }
            }
        }
    }

    Thread.currentThread().getName() 此方法的作用是获取线程名

    输出结果:

      从上面输出结果可以看出,当Thread-0进入睡眠状态之后,Thread-1并没有去执行具体的任务。只有当Thread-0执行完之后,此时Thread-0释放了对象锁,Thread-1才开始执行。

      注意,如果调用了sleep方法,必须捕获InterruptedException异常或者将该异常向上层抛出。当线程睡眠时间满后,不一定会立即得到执行,因为此时可能CPU正在执行其他的任务。所以说调用sleep方法相当于让线程进入阻塞状态。

      4)yield方法

      调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。

      注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。

      5)join方法

      join方法有三个重载版本:

    1
    2
    3
    join()
    join(long millis)     //参数为毫秒
    join(long millis,int nanoseconds)    //第一参数为毫秒,第二个参数为纳秒

       假如在main线程中,调用thread.join方法,则main方法会等待thread线程执行完毕或者等待一定的时间。如果调用的是无参join方法,则等待thread执行完毕,如果调用的是指定了时间参数的join方法,则等待一定的时间。

      看下面一个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public class Test {
         
        public static void main(String[] args) throws IOException  {
            System.out.println("进入线程"+Thread.currentThread().getName());
            Test test = new Test();
            MyThread thread1 = test.new MyThread();
            thread1.start();
            try {
                System.out.println("线程"+Thread.currentThread().getName()+"等待");
                thread1.join();
                System.out.println("线程"+Thread.currentThread().getName()+"继续执行");
            catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        
         
        class MyThread extends Thread{
            @Override
            public void run() {
                System.out.println("进入线程"+Thread.currentThread().getName());
                try {
                    Thread.currentThread().sleep(5000);
                catch (InterruptedException e) {
                    // TODO: handle exception
                }
                System.out.println("线程"+Thread.currentThread().getName()+"执行完毕");
            }
        }
    }

    结果:Thread-0调用完毕后才继续执行main线程

    wait方法会让线程进入阻塞状态,并且会释放线程占有的锁,并交出CPU执行权限。

    由于wait方法会让线程释放对象锁,所以join方法同样会让线程释放对一个对象持有的锁。具体的wait方法使用在后面文章中给出。

      6)interrupt方法

      interrupt,顾名思义,即中断的意思。单独调用interrupt方法可以使得处于阻塞状态的线程抛出一个异常,也就说,它可以用来中断一个正处于阻塞状态的线程;另外,通过interrupt方法和isInterrupted()方法来停止正在运行的线程。

      下面看一个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public class Test {
         
        public static void main(String[] args) throws IOException  {
            Test test = new Test();
            MyThread thread = test.new MyThread();
            thread.start();
            try {
                Thread.currentThread().sleep(2000);
            catch (InterruptedException e) {
                 
            }
            thread.interrupt();
        
         
        class MyThread extends Thread{
            @Override
            public void run() {
                try {
                    System.out.println("进入睡眠状态");
                    Thread.currentThread().sleep(10000);
                    System.out.println("睡眠完毕");
                catch (InterruptedException e) {
                    System.out.println("得到中断异常");
                }
                System.out.println("run方法执行完毕");
            }
        }
    }

       输出结果:

      

      从这里可以看出,通过interrupt方法可以中断处于阻塞状态的线程。那么能不能中断处于非阻塞状态的线程呢?看下面这个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public class Test {
         
        public static void main(String[] args) throws IOException  {
            Test test = new Test();
            MyThread thread = test.new MyThread();
            thread.start();
            try {
                Thread.currentThread().sleep(2000);
            catch (InterruptedException e) {
                 
            }
            thread.interrupt();
        
         
        class MyThread extends Thread{
            @Override
            public void run() {
                int i = 0;
                while(i<Integer.MAX_VALUE){
                    System.out.println(i+" while循环");
                    i++;
                }
            }
        }
    }

       运行该程序会发现,while循环会一直运行直到变量i的值超出Integer.MAX_VALUE。所以说直接调用interrupt方法不能中断正在运行中的线程。

      但是如果配合isInterrupted()能够中断正在运行的线程,因为调用interrupt方法相当于将中断标志位置为true,那么可以通过调用isInterrupted()判断中断标志是否被置位来中断线程的执行。比如下面这段代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public class Test {
         
        public static void main(String[] args) throws IOException  {
            Test test = new Test();
            MyThread thread = test.new MyThread();
            thread.start();
            try {
                Thread.currentThread().sleep(2000);
            catch (InterruptedException e) {
                 
            }
            thread.interrupt();
        
         
        class MyThread extends Thread{
            @Override
            public void run() {
                int i = 0;
                while(!isInterrupted() && i<Integer.MAX_VALUE){
                    System.out.println(i+" while循环");
                    i++;
                }
            }
        }
    }

       运行会发现,打印若干个值之后,while循环就停止打印了。

      但是一般情况下不建议通过这种方式来中断线程,一般会在MyThread类中增加一个属性 isStop来标志是否结束while循环,然后再在while循环中判断isStop的值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class MyThread extends Thread{
            private volatile boolean isStop = false;
            @Override
            public void run() {
                int i = 0;
                while(!isStop){
                    i++;
                }
            }
             
            public void setStop(boolean stop){
                this.isStop = stop;
            }
        }

       那么就可以在外面通过调用setStop方法来终止while循环。

      7)stop方法

      stop方法已经是一个废弃的方法,它是一个不安全的方法。因为调用stop方法会直接终止run方法的调用,并且会抛出一个ThreadDeath错误,如果线程持有某个对象锁的话,会完全释放锁,导致对象状态不一致。所以stop方法基本是不会被用到的。

      8)destroy方法

      destroy方法也是废弃的方法。基本不会被使用到。

      以下是关系到线程属性的几个方法:

      1)getId

      用来得到线程ID

      2)getName和setName

      用来得到或者设置线程名称。

      3)getPriority和setPriority

      用来获取和设置线程优先级。

      4)setDaemon和isDaemon

      用来设置线程是否成为守护线程和判断线程是否是守护线程。

      守护线程和用户线程的区别在于:守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。

      Thread类有一个比较常用的静态方法currentThread()用来获取当前线程。

      在上面已经说到了Thread类中的大部分方法,那么Thread类中的方法调用到底会引起线程状态发生怎样的变化呢?下面一幅图就是在上面的图上进行改进而来的:

    展开全文
  • JAVA线程之Thread类详解

    万次阅读 多人点赞 2018-05-31 09:38:18
    ss

    Thread类用于操作线程,是所以涉及到线程操作(如并发)的基础。本文将通过源码对Thread类的功能作用进行分析。

    一、属性

        /* Make sure registerNatives is the first thing <clinit> does. */
        private static native void registerNatives();
        static {
            registerNatives();
        }
    
        private volatile String name;
        private int            priority;
        private Thread         threadQ;
        private long           eetop;
    
        /* Whether or not to single_step this thread. */
        private boolean     single_step;
    
        /* Whether or not the thread is a daemon thread. */
        private boolean     daemon = false;
    
        /* JVM state */
        private boolean     stillborn = false;
    
        /* What will be run. */
        private Runnable target;
    
        /* The group of this thread */
        private ThreadGroup group;
    
        /* The context ClassLoader for this thread */
        private ClassLoader contextClassLoader;
    
        /* The inherited AccessControlContext of this thread */
        private AccessControlContext inheritedAccessControlContext;
    
        /* For autonumbering anonymous threads. */
        private static int threadInitNumber;
        private static synchronized int nextThreadNum() {
            return threadInitNumber++;
        }
    
        /* ThreadLocal values pertaining to this thread. This map is maintained
         * by the ThreadLocal class. */
        ThreadLocal.ThreadLocalMap threadLocals = null;
        /*
         * InheritableThreadLocal values pertaining to this thread. This map is
         * maintained by the InheritableThreadLocal class.
         */
    
        ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    
        /*
         * The requested stack size for this thread, or 0 if the creator did
         * not specify a stack size.  It is up to the VM to do whatever it
         * likes with this number; some VMs will ignore it.
         */
        private long stackSize;
    
        /*
         * JVM-private state that persists after native thread termination.
         */
        private long nativeParkEventPointer;
    
        /*
         * Thread ID
         */
        private long tid;
    
        /* For generating thread ID */
        private static long threadSeqNumber;
    
        /* Java thread status for tools,
         * initialized to indicate thread 'not yet started'
         */
    
        private volatile int threadStatus = 0;
      volatile Object parkBlocker;
    
        /* The object in which this thread is blocked in an interruptible I/O
         * operation, if any.  The blocker's interrupt method should be invoked
         * after setting this thread's interrupt status.
         */
        private volatile Interruptible blocker;
        private final Object blockerLock = new Object();
    
        public final static int MIN_PRIORITY = 1;
    
        /**
         * The default priority that is assigned to a thread.
         */
        public final static int NORM_PRIORITY = 5;
    
        /**
         * The maximum priority that a thread can have.
         */
        public final static int MAX_PRIORITY = 10;
        public enum State {
            /**
             * Thread state for a thread which has not yet started.
             */
            NEW,
    
            /**
             * Thread state for a runnable thread.  A thread in the runnable
             * state is executing in the Java virtual machine but it may
             * be waiting for other resources from the operating system
             * such as processor.
             */
            RUNNABLE,
    
            /**
             * Thread state for a thread blocked waiting for a monitor lock.
             * A thread in the blocked state is waiting for a monitor lock
             * to enter a synchronized block/method or
             * reenter a synchronized block/method after calling
             * {@link Object#wait() Object.wait}.
             */
            BLOCKED,
    
            /**
             * Thread state for a waiting thread.
             * A thread is in the waiting state due to calling one of the
             * following methods:
             * <ul>
             *   <li>{@link Object#wait() Object.wait} with no timeout</li>
             *   <li>{@link #join() Thread.join} with no timeout</li>
             *   <li>{@link LockSupport#park() LockSupport.park}</li>
             * </ul>
             *
             * <p>A thread in the waiting state is waiting for another thread to
             * perform a particular action.
             *
             * For example, a thread that has called <tt>Object.wait()</tt>
             * on an object is waiting for another thread to call
             * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
             * that object. A thread that has called <tt>Thread.join()</tt>
             * is waiting for a specified thread to terminate.
             */
            WAITING,
    
            /**
             * Thread state for a waiting thread with a specified waiting time.
             * A thread is in the timed waiting state due to calling one of
             * the following methods with a specified positive waiting time:
             * <ul>
             *   <li>{@link #sleep Thread.sleep}</li>
             *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
             *   <li>{@link #join(long) Thread.join} with timeout</li>
             *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
             *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
             * </ul>
             */
            TIMED_WAITING,
    
            /**
             * Thread state for a terminated thread.
             * The thread has completed execution.
             */
            TERMINATED;
        }

    此处重点说一下线程的优先级和状态。

    1.线程优先级


        private int  priority;
    
        public final static int MIN_PRIORITY = 1;
        public final static int NORM_PRIORITY = 5;
        public final static int MAX_PRIORITY = 10;
    
       public final void setPriority(int newPriority) {
            ThreadGroup g;
            checkAccess();
            if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
                throw new IllegalArgumentException();
            }
            if((g = getThreadGroup()) != null) {
                if (newPriority > g.getMaxPriority()) {
                    newPriority = g.getMaxPriority();
                }
                setPriority0(priority = newPriority);
            }
        }
    
        public final int getPriority() {
            return priority;
        }

    线程执行有优先级,优先级越高先执行机会越大(并不是一定先执行!!)。优先级用int的priority参数表示。
    线程优先级最高为10,最低为1。默认为5
    2.线程的状态

     public enum State {
            NEW,
            RUNNABLE,
            BLOCKED,
            WAITING,
            TIMED_WAITING,
            TERMINATED;
        }
          public State getState() {
            return sun.misc.VM.toThreadState(threadStatus);
        }

    Thread对象共有6种状态:NEW(新建),RUNNABLE(运行),BLOCKED(阻塞),WAITING(等待),TIMED_WAITING(有时间的等待),TERMINATED(终止);状态转换如下:
    这里写图片描述

    也有一种说法,我认为也可以:
    线程只有”就绪”、”阻塞”、”运行”三种状态(新建[NEW]”和”终止[TERMINATED]”状态的线程并不是线程,只是代表一个线程对象还存在):
    1. RUNNABLE,对应”就绪”和”运行”两种状态,也就是说处于就绪和运行状态的线程在java.lang.Thread中都表现为”RUNNABLE”
    2. BLOCKED,对应”阻塞”状态,此线程需要获得某个锁才能继续执行,而这个锁目前被其他线程持有,所以进入了被动的等待状态,直到抢到了那个锁,才会再次进入”就绪”状态
    3. WAITING,对应”阻塞”状态,代表此线程正处于无限期的主动等待中,直到有人唤醒它,它才会再次进入就绪状态
    4. TIMED_WAITING,对应”阻塞”状态,代表此线程正处于有限期的主动等待中,要么有人唤醒它,要么等待够了一定时间之后,才会再次进入就绪状态

    二、构造器

        public Thread() {
            init(null, null, "Thread-" + nextThreadNum(), 0);
        }
    
        public Thread(Runnable target) {
            init(null, target, "Thread-" + nextThreadNum(), 0);
        }
    
        public Thread(ThreadGroup group, Runnable target) {
            init(group, target, "Thread-" + nextThreadNum(), 0);
        }
    
       public Thread(String name) {
            init(null, null, name, 0);
        }
    
        public Thread(ThreadGroup group, String name) {
            init(group, null, name, 0);
        }
    
        public Thread(Runnable target, String name) {
            init(null, target, name, 0);
        }
    
        public Thread(ThreadGroup group, Runnable target, String name) {
            init(group, target, name, 0);
        }
    
    
        public Thread(ThreadGroup group, Runnable target, String name,
                      long stackSize) {
            init(group, target, name, stackSize);
        }
         private void init(ThreadGroup g, Runnable target, String name,long stackSize) {
            init(g, target, name, stackSize, null, true);
        }
        private void init(ThreadGroup g, Runnable target, String name,
                          long stackSize, AccessControlContext acc,
                          boolean inheritThreadLocals) {
            if (name == null) {
                throw new NullPointerException("name cannot be null");
            }
    
            this.name = name;
    
            Thread parent = currentThread();
            SecurityManager security = System.getSecurityManager();
            if (g == null) {
                /* Determine if it's an applet or not */
    
                /* If there is a security manager, ask the security manager
                   what to do. */
                if (security != null) {
                    g = security.getThreadGroup();
                }
    
                /* If the security doesn't have a strong opinion of the matter
                   use the parent thread group. */
                if (g == null) {
                    g = parent.getThreadGroup();
                }
            }
    
            g.checkAccess();
    
            if (security != null) {
                if (isCCLOverridden(getClass())) {
                    security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
                }
            }
    
            g.addUnstarted();
    
            this.group = g;
            this.daemon = parent.isDaemon();
            this.priority = parent.getPriority();
            if (security == null || isCCLOverridden(parent.getClass()))
                this.contextClassLoader = parent.getContextClassLoader();
            else
                this.contextClassLoader = parent.contextClassLoader;
            this.inheritedAccessControlContext =
                    acc != null ? acc : AccessController.getContext();
            this.target = target;
            setPriority(priority);
            if (inheritThreadLocals && parent.inheritableThreadLocals != null)
                this.inheritableThreadLocals =
                    ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
            /* Stash the specified stack size in case the VM cares */
            this.stackSize = stackSize;
    
            /* Set thread ID */
            tid = nextThreadID();
        }

    通过以上代码可以看出,Thread()对外提供了8个构造器,但是都是接收不同参数,然后调用init(ThreadGroup g, Runnable target, String name, long stackSize)方法。故我们只需分析次init()方法即可。
    init()方法共有4个参数,分别代表:

    1. ThreadGroup g 指定当前线程的线程组,未指定时线程组为创建该线程所属的线程组。线程组可以用来管理一组线程,通过activeCount() 来查看活动线程的数量。其他没有什么大的用处。 
    2. Runnable target 指定运行其中的Runnable,一般都需要指定,不指定的线程没有意义,或者可以通过创建Thread的子类并重新run方法。
    3. String name 线程的名称,不指定自动生成。
    4. long stackSize 预期堆栈大小,不指定默认为0,0代表忽略这个属性。与平台相关,不建议使用该属性。

    三、public方法

    Thread Thread.currentThread() :获得当前线程的引用。获得当前线程后对其进行操作。
    Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() :返回线程由于未捕获到异常而突然终止时调用的默认处理程序。
    int Thread.activeCount():当前线程所在线程组中活动线程的数目。
    void dumpStack() :将当前线程的堆栈跟踪打印至标准错误流。
    int enumerate(Thread[] tarray) :将当前线程的线程组及其子组中的每一个活动线程复制到指定的数组中。
    Map<Thread,StackTraceElement[]> getAllStackTraces() :返回所有活动线程的堆栈跟踪的一个映射。
    boolean holdsLock(Object obj) :当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
    boolean interrupted() :测试当前线程是否已经中断。
    void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) :设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。
    void sleep(long millis) :休眠指定时间
    void sleep(long millis, int nanos) :休眠指定时间
    void yield() :暂停当前正在执行的线程对象,并执行其他线程。意义不太大
    
    void checkAccess() :判定当前运行的线程是否有权修改该线程。
    ClassLoader getContextClassLoader() :返回该线程的上下文 ClassLoader。
    long getId() :返回该线程的标识符。
    String getName() :返回该线程的名称。
    int getPriority() :返回线程的优先级。
    StackTraceElement[] getStackTrace() :返回一个表示该线程堆栈转储的堆栈跟踪元素数组。
    Thread.State getState() :返回该线程的状态。
    ThreadGroup getThreadGroup() :返回该线程所属的线程组。
    Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() :返回该线程由于未捕获到异常而突然终止时调用的处理程序。
    void interrupt() :中断线程。
    boolean isAlive() :测试线程是否处于活动状态。
    boolean isDaemon() :测试该线程是否为守护线程。
    boolean isInterrupted():测试线程是否已经中断。
    void join() :等待该线程终止。
    void join(long millis) :等待该线程终止的时间最长为 millis 毫秒。
    void join(long millis, int nanos) :等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
    void run() :线程启动后执行的方法。
    void setContextClassLoader(ClassLoader cl) :设置该线程的上下文 ClassLoader。
    void setDaemon(boolean on) :将该线程标记为守护线程或用户线程。
    void start():使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
    String toString():返回该线程的字符串表示形式,包括线程名称、优先级和线程组。

    在此重点是Thread currentThread(),void run() ,void start(),boolean interrupted() ,void interrupt(),boolean isInterrupted(),void sleep(long millis) ,void sleep(long millis, int nanos) ,void join() ,
    void join(long millis) ,void join(long millis, int nanos) 这几个方法
    1.Thread currentThread()
    该方法是本地静态方法,用于获取当前线程,返回线程对象。

       public static native Thread currentThread();

    2.void run()
    是线程执行任务的主要代码。

       public void run() {
            if (target != null) {
                target.run();
            }
        }

    当target不为空时,执行target的run方法。若target为空,则需要重写此方法,方法内是业务逻辑
    3.void start()
    使得该线程开始执行;Java 虚拟机调用该线程的 run 方法。

      public synchronized void start() {
            if (threadStatus != 0)
                throw new IllegalThreadStateException();
    
            group.add(this);
    
            boolean started = false;
            try {
                start0();
                started = true;
            } finally {
                try {
                    if (!started) {
                        group.threadStartFailed(this);
                    }
                } catch (Throwable ignore) {
                    /* do nothing. If start0 threw a Throwable then
                      it will be passed up the call stack */
                }
            }
        }
    
        private native void start0();

    4.boolean interrupted() & void interrupt() & boolean isInterrupted()
    这三个方法是针对线程中断标记的方法,

        public static boolean interrupted() {
            return currentThread().isInterrupted(true);
        }
         public boolean isInterrupted() {
            return isInterrupted(false);
        }
        public void interrupt() {
            if (this != Thread.currentThread())
                checkAccess();
    
            synchronized (blockerLock) {
                Interruptible b = blocker;
                if (b != null) {
                    interrupt0();           // Just to set the interrupt flag
                    b.interrupt(this);
                    return;
                }
            }
            interrupt0();
        }
    
        private native boolean isInterrupted(boolean ClearInterrupted);

    interrupt():中断本线程(将中断状态标记为true)
    isInterrupted():检测本线程是否已经中断 。如果已经中断,则返回true,否则false。中断状态不受该方法的影响。 如果中断调用时线程已经不处于活动状态,则返回false。
    interrupted():检测当前线程是否已经中断 。如果当前线程存在中断,返回true,并且修改标记为false。再调用isIterruoted()会返回false。如果当前线程没有中断标记,返回false,不会修改中断标记。
    测试代码:

    public class TestThread {
        public static void main(String[] args) throws Exception{
            test();
        }
    
        public static void test() throws Exception{
            Thread t1 = new Thread(new MyThread());
            Thread t2 = new Thread(new MyThread());
            t1.start();
            t1.interrupt();
            System.out.println("1"+t1.isInterrupted());
            System.out.println("2"+t1.isInterrupted());
            System.out.println("3"+t1.interrupted());
            t2.start();
    
        }
    
    }
    
    class MyThread extends Thread {
    
        @Override
        public void run() {
    
            for (int i = 0; i < 10000; i++) {
    
            }
            System.out.println("4"+currentThread().getName()+interrupted());
            System.out.println("5"+currentThread().getName()+interrupted());
    
        }
    }

    执行结果:

    1true
    4Thread-1true
    2false
    5Thread-1false
    3false
    4Thread-3false
    5Thread-3false

    5.void sleep(long millis) & void sleep(long millis, int nanos)
    这两个方法是让线程休眠

     public static void sleep(long millis, int nanos) throws InterruptedException {
            if (millis < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
    
            if (nanos < 0 || nanos > 999999) {
                throw new IllegalArgumentException("nanosecond timeout value out of range");
            }
    
            if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
                millis++;
            }
    
            sleep(millis);
        }
       public static native void sleep(long millis) throws InterruptedException;

    如上,两个参数的sleep只是将nanos转为millis(四舍五入转换),调用sleep(millis)方法。
    sleep(millis)是本地方法,让当前线程休眠指定时间。
    sleep不释放锁。
    6.void join() & void join(long millis) & void join(long millis, int nanos)
    这三个方法是让等待该线程终止。

        public final void join() throws InterruptedException {
            join(0);
        }
        public final synchronized void join(long millis, int nanos)throws InterruptedException {
    
            if (millis < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
    
            if (nanos < 0 || nanos > 999999) {
                throw new IllegalArgumentException(
                                    "nanosecond timeout value out of range");
            }
    
            if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
                millis++;
            }
    
            join(millis);
        }
       public final synchronized void join(long millis)throws InterruptedException {
            long base = System.currentTimeMillis();
            long now = 0;
    
            if (millis < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
    
            if (millis == 0) {
                while (isAlive()) {
                    wait(0);
                }
            } else {
                while (isAlive()) {
                    long delay = millis - now;
                    if (delay <= 0) {
                        break;
                    }
                    wait(delay);
                    now = System.currentTimeMillis() - base;
                }
            }
        }

    当传入参数为0时,代表一直等待到结束。

    展开全文
  • C++多线程(一)thread

    万次阅读 多人点赞 2018-04-10 16:28:29
    thread&gt;,&lt;mutex&gt;,&lt;condition_variable&gt;和&lt;future&gt;。 &lt;atomic&gt;:该头文主要声明了两个类, std::atomic 和 std::atomic_flag...
  • thread dump分析

    千次阅读 2018-08-02 14:07:11
    一、thread dump信息获取 1、发送信号 * In Unix, use "kill -3 &lt;pid&gt;" where pid is the Process ID of the JVM.(kill 信号列表) * In Windows, press CTRL+BREAK on the window where ...
  • 【多线程】Thread和Runnable区别

    千次阅读 多人点赞 2019-06-17 15:13:43
    实现方式Thread类 线程?  线程是进程中独立运行的子任务,比如我们运行的QQMuic.exe的时候,然后就会有很多的子任务,而且不同的子任务可以共同工作,这时候每一个子任务就是一个线程,多个子任务共同工作,就是多...
  • Java Thread类源码详解

    千次阅读 2019-12-23 16:26:23
    Java所有多线程的实现,均通过封装Thread类实现,所以深入Thread类,对深入理解java多线程很有必要 构造函数: Thread的构造函数,采用缺省的方式实现: //传入Runnable接口实现 Thread...
  • Android Thread 浅析和使用小结

    千次阅读 2018-12-22 14:08:17
    创建(new) Thread thread=new Thread; 就绪(runnable) thread.start(); 运行(running) 线程只能从就绪状态进入到运行状态 阻塞(blocked) 该状态是线程因为某种原因放弃了cpu使用权限,暂时停止运行...
  • 绕过discuz论坛阅读或下载权限

    万次阅读 2014-07-18 15:31:07
    discuz X3.1 文件下载提权方案 利用工具和条件: 1.站长工具base64在线加解密 http://tool.chinaz.com/Tools/Base64.aspx 2.能正常登录的普通帐号 3.能浏览vip专区的内容,但是文件的下载链接为没有权限的链接 ...
  • Thread.currentThread()与this的区别

    万次阅读 多人点赞 2017-03-02 20:16:18
    Thread.currentThread()与this的区别
  • Java线程池(ExecutorService)使用

    万次阅读 2017-07-31 17:48:38
    一、前提/** * 线程运行demo,运行时打出线程id以及传入线程中参数 */ public class ThreadRunner implements Runnable { private final SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss.SSS");...
  • 我们进行程序开发的时候,肯定避免不了要处理并发的情况。 一般并发的手段有采用多进程和多线程。 但线程比进程更轻量化,系统开销一般也更低,所以大家更倾向于用多线程的方式处理并发的情况。...thread...
  • cocos2d-x引擎在内部实现了一个庞大的主循环,每帧之间更新界面,如果耗时的操作放到了主线程中,游戏的界面就会卡,这是不能容忍的,游戏最基本的条件就是流畅性,这就是为什么游戏开发选择C++的原因。...
  • Java多线程中锁的理解与使用

    万次阅读 多人点赞 2017-10-14 18:45:51
    锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等 )
  • if (!(Test-Path -Path $PROFILE)) { New-Item -ItemType File -Path $PROFILE -Force }
  • extends Thread 与 implements Runnable 的区别

    万次阅读 多人点赞 2012-05-01 20:26:54
    1、通过实现Runnable接口创建线程 (1).定义一个类实现Runnable接口,重写接口中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。 ...(2)....(3)....调用Thread对象的start()方法,启动线程
  • python 多线程 start_new_thread()

    万次阅读 2015-04-22 15:00:33
    一、简述 CPython实现细节: 由于GIL(Global Interpreter Lock),在CPython中一次只能有一个线程来执行python代码,不过有些面向执行的库可以克服这个限制。如果想要使你的应用程序更好的利用计算机资源的话,...
  • 8月9日在service中创建子线程时...java.lang.RuntimeException: Can't create handler inside thread Thread that has not called Looper.prepare() 这个问题。代码如下 new Thread(new Runnable() { @Override ...
  • Thread类常用方法

    万次阅读 2014-05-23 22:53:23
    Thread类构造方法: 1.Thread(); 2.Thread()
1 2 3 4 5 ... 20
收藏数 1,419,941
精华内容 567,976
关键字:

thread