在任意一个时间点:一个线程只能有且只有其中一种状态。
新建(new)状态:创建后尚未启动的线程就是出于这种状态。
运行(Runable)状态:Runable包括了操作系统线程状态中的Running和Ready,也就是出于此状态的线程有可能正在执行,也有可能等待CPU为它分配执行时间。
无限期等待(waiting)状态:处于该状态下的线程不会被分配CPU执行时间,它们要等待被其他线程显示的唤醒。以下的方法会让线程陷入无限期的等待状态。
- 没有设置timeout参数的Object.wait()方法。
- 没有设置timeout参数的Thread.join()方法
- LockSupport.park()方法。
限期等待(Timed Waiting)状态:处于该状态下的线程不会被分配CPU执行时间,但是不需要等待其他线程显式的唤醒。而是在一定时间之后它们会由系统自动唤醒。一以下方法会让线程进入限期等待的状态:
- Thread.sleep()方法
- 设置了timeout参数的Object.wait()方法
- 设置了timeout参数的Thread.join()方法
- LockSupport.parkNanos()方法
- LockSupport.parkUntil()方法
阻塞(blocked)状态:阻塞状态,顾名思义就是线程被阻塞了,在程序等待进入同步区域的时候,线程将进入这种状态。“阻塞状态” 和“等待状态” 的区别:“阻塞状态”在等待着获取一个排它锁。如果另一个线程获得了排它锁,然而这个线程申请获得这个排它锁的时候就会进入“阻塞状态”。“等待状态”则是在等待一段时间后,或者有唤醒动作的发生。
结束(terminated)状态:已终止线程的线程状态。线程结束执行。
线程状态转换关系如图(图来自深入理解jvm虚拟机)
接下来就是说明让线程进入等待状态的一些方法:
1、Object类
Object.wait()方法:让当前线程立即释放当前获得的锁并进入无限等待状态。
Object.wait(long timeout)方法:让当前线程立即释放当前获得的锁并进入限期等待状态,timeout参数的单位是毫秒。唤醒:①其他线程调用notify() 或者notifyAll()、②超过timeout毫秒之后由系统自动唤醒。
Object.wait(long timeout,int naos)方法:同wait(long timeout)方法,多出来的naos参数则是单位则是纳秒,所以如果被系统自动唤醒时间是:(timeout*1000000+naos)纳秒
notify()方法:随机唤醒一个处于“等待状态”的线程(API文档上If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation)。
notifyAll()方法:唤醒所有处于“等待状态”的线程。然后所有的线程去竞争这个排他锁(优先级高的线程获得的锁的概率大)。无论notify()方法还是notifyAll()方法不会立即释放获得的锁,而是等同步代码块执行完毕后才会释放锁。
注意:wait方法和notify方法必须是同一个锁才行。
wait方法和notify方法必须在同步代码块中使用。
2、Thread类
Thread.join()方法:等待当前线程执行完毕后再执行join()后面的代码。eg:t1.join()就是等待t1线程执行完毕后,再执行后面的代码。
Thread.join(long millis)方法:至多等待millis毫秒当前线程执行,超过这个时间后,系统会主动notifyAll。
Thread.join(longmillis,int naos)方法:至多等待millis毫秒+naos纳秒当前线程执行,超过这个时间后,系统会主动notifyAll。
package com.cn.hn.test;
public class ThreadSimple implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName()+"begin:"+ System.nanoTime());
try {
Thread.sleep(1800);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"end:"+ System.nanoTime());
};
public static void main(String[] args){
ThreadSimple test1 = new ThreadSimple();
Thread t1 = new Thread(test1);
Thread t2 = new Thread(test1);
t1.setName("test1");
t2.setName("test2");
System.out.println("main"+Thread.currentThread().getName()+System.nanoTime());
t1.start();
try {
t1.join();
//t1.join(100);
t2.start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("main"+Thread.currentThread().getName()+System.nanoTime());
}
}
Thread.sleep(long millis)方法:让当前执行线程睡眠millis毫秒。超过这个时间后,系统会主动notify该线程。
Thread.sleep(long millis ,int naos)方法:让当前执行线程睡眠millis毫秒+naos纳秒,超过这个时间后,系统会主动notify该线程。
注意:sleep()方法并不释放当前线程持有的锁,只是让当前线程让出CPU,并陷入睡眠状态
Thread.run()方法,一个线程的执行逻辑。调用Thread.start()方法会执行run()方法的内容。该方法没有返回值。如果要求有返回值,可以使用Callable()。
Thread.start()方法:启动一个线程。进入Ready状态,如果获取了cpu执行时间。然后会调用run()方法.
Thread.yield()方法:当前线程让出CPU执行时间,然后处于ready状态。然后该线程和其他处于ready状态的线程一起竞争CPU执行时间。
Thread.interrupt()方法:尝试去中断该线程。它会将当前线程中断标志位设置为TRUE。至于是否中断以及中断的过程,再开一篇说好了。