您的位置:首页 > 编程语言 > Java开发

Java并发编程基础-线程-状态转换

2018-07-18 10:19 337 查看
转化图表

一个线程的起点都是初始态,终点都是终止态(程序正常运行结束后),中间运行态可能向阻塞、等待和超时等待几种状态进行转化,从《Java并发编程艺的艺术》第四章中拿一张线程状态转化图,如下所示:



PS:图上有一处错误,运行状态转换为等待状态的Object.join()应为Thead.join()

状态转化相关方法和描述如下表:

开始状态结束状态相关方法描述
NEWREADYThread.start()
READYRUNNING等待CPU调度
RUNNINGREADYThread.yield()让出CPU使用权
RUNNINGWAITINGObject.wait()
Thread.join()
LockSupport.park()
让线程进入等待状态
WAITINGREADYThread.interrupt()
Object.notify()
Object.notifyAll()
LockSupport.unpark(Thread)
唤醒或者打断等待线程,进入就绪状态,等待CPU调度
RUNNINGTIMED_WAITINGThread.sleep(long)
Object.wait(long)
Thread.join(long)
LockSupport.parkNanos(long)
LockSupport.parkUntil(long)
让线程进入超时等待状态
TIMED_WAITINGREADYThread.interrupt()
Object.notify()
Object.notifyAll()
LockSupport.unpark(Thread)
唤醒或者打断超时等待线程,进入就绪状态,等待CPU调度
RUNNINGBLOCKEDsynchonized 代码块或方法

让线程进入到阻塞状态
BLOCKEDREADY获取到锁,让线程进入就绪状态,等待CPU调度
RUNNINGTERMINATED线程执行完成后,自行结束
几点说明

Thread.interrupt()
线程被sleep()\wait()\join()阻塞的时候,调用线程的此方法可以清除打断状态并抛出一个InterruptedException异常,需要注意的是:线程正常运行时,不会被打断。以下是一个例子,分别打印运行线程和阻塞线程在调用interrupt方法前后的打断状态
Thread runningThread = new Thread(new Runnable() {
@Override
public void run() {
for (;;){

}
}
},"runningThread");
Thread blockedThread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
// e.printStackTrace();
}
}
},"blockedThread");
runningThread.start();
blockedThread.start();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
runningThread.interrupt();
blockedThread.interrupt();
System.out.println(runningThread.getName() + " interrupted status:" + runningThread.isInterrupted());
System.out.println(blockedThread.getName() + " interrupted status:" + blockedThread.isInterrupted());

//从输出中可以发现runningThread的打断标记变为true,blockedThread的打断标记依然为false(其实是重置了)
//另外程序还在一直运行中,证明runningThread没有被打断
before interrupt,runningThread interrupted status:false
before interrupt,blockedThread interrupted status:false
after interrupt,runningThread interrupted status:true
after interrupt,blockedThread interrupted status:false


sleep()和wait()
sleep()方法不会丢失任何监视器的所有权,可以理解sleep()会一直持有锁,而wait()会丢失掉当前监视器的所有权并使当前线程等待其他线程唤醒,以下是sleep()和wait()方法的测试例子
/**
* 阻塞对象
*/
private static class BlockObj {

/**
*  睡眠并打印
*/

public synchronized void sleepAndSay() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " begin sleep!");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName + " end sleep!");
}

/**
* 等待并打印
*/
public  synchronized void waitAndSay() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " begin wait!");
try {
this.wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName + " end wait!");

}
}
/**
* 睡眠测试
*/
private void testSleep() {
//
final BlockObj blockObj = new BlockObj();
Thread sleepThread1 = new Thread(new Runnable() {
@Override
public void run() {
blockObj.sleepAndSay();
}
}, "sleepThread1");
Thread sleepThread2 = new Thread(new Runnable() {
@Override
public void run() {
blockObj.sleepAndSay();
}
},"sleepThread2");

sleepThread1.start();

try {
//主线程睡眠3秒让sleepThread1充分运行
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
sleepThread2.start();

}

/**
* 等待测试
*/
private void testWait() {
final BlockObj blockObj = new BlockObj();
Thread waitThread1 = new Thread(new Runnable() {
@Override
public void run() {
blockObj.waitAndSay();
}
}, "waitThread1");
Thread waitThread2 = new Thread(new Runnable() {
@Override
public void run() {
blockObj.waitAndSay();
}
},"waitThread2");

waitThread1.start();

try {
//主线程睡眠3秒让waitThread1充分运行
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitThread2.start();

}

//睡眠测试结果
//sleepThead1睡眠后,sleepThread2依然被阻塞,无法开始
//sleepThread1睡眠结束,运行完成后,sleepThread2才开始运行
//证明sleep会一直持有锁
sleepThread1 begin sleep!
sleepThread1 end sleep!
sleepThread2 begin sleep!
sleepThread2 end sleep!

//等待测试结果
//waitThread1进入等待状态后,过了指定的3秒,waitThread2开始运行
//waitThread2进入等待状态后,waitThead1等待了指定的5秒后,又开始继续运行
//证明wait是不会持有锁的
waitThread1 begin wait!
waitThread2 begin wait!
waitThread1 end wait!
waitThread2 end wait!


Thread.join()底层实际上是调用了Object.wait(),因此同样能让线程进入等待状态,源码如下:
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;
}
}
}


Object.wait()、notify()、notifyAll()必须在获取监控器(在HotSpot JVM中可以理解为锁)的条件下进行,通常是在Synchonized关键字修饰的代码块或者方法中运行。wait()官方注释上的一个用法如下:

*     synchronized (obj) {
*         while (<condition does not hold>)
*             obj.wait();
*         ... // Perform action appropriate to condition
*     }


参考书籍及网址:

《Java并发编程的艺术》

《深入理解Java虚拟机》

PS:研究基于MAC+Idea+JDK1.8 64位

Keep Calm and Carry on!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java IntelliJ IDEA JDK