Java中的线程有六种状态,使用线程Thread内的枚举类来实现,以下,我对每一个状态都进行了必定的解释。html
public enum State { /** 表示一个线程还没启用(即未调用start方法)*/ NEW, /** * JVM中执行的线程都是处于这个状态的,可是处于这个状态不必定在JVM中执行, * 也就是说,只有这个状态有资格被JVM调度从而得到时间片执行。 */ RUNNABLE, /** * 线程在等待获取锁资源从而进入阻塞状态, * 在这个状态中,其一直监视锁的动态,随时准备抢占锁 * 若得到锁资源,从新进入RUNNABLE状态 */ BLOCKED, /** * 当调用Object.wait、Thread.join或者LockSupport类的park方法的时候,线程进入此状态, * 该状态若无其余线程主动唤醒,则无期限的等待。 * 唤醒的方法包括:Object.notify(唤醒随机一个)、Object.notifyAll(唤醒所有线程), * 被唤醒的线程从新进入RUNNABLE状态 */ WAITING, /** * 同WAITING状态,不过不一样的是调用的方法加上了时间的限制, * 例如:Object.wait(10)、Thread.sleep(10)、Thread.join(10)、LockSupport.parkNanos(10)、LockSupport.parkUntil(10)这些方法 * 唤醒的方法有两种: * 一、时间过时。 * 二、其余线程调用了notify或者notifyAll * 唤醒以后一样进入RUNNABLE状态 */ TIMED_WAITING, /** 线程的终点(正常死亡或者被终止)*/ TERMINATED; }
除了NEW和TERMINATED以外,其余的状态都是能够相互转换的,其转换过程以下图所示编程
这里特别讲一下RUNNABLE状态,在这个状态中线程并不必定在执行程序,只有被JVM调度的线程才能得到执行的时间片,而且只有这个状态的线程才可以得到时间片,换句话说,被JVM调度而且得到时间片是只属于处于RUNNABLE状态线程的权利。为了便于理解,能够将RUNNABLE分红Runnable和Running两个状态(固然,你也能够换成其余的,这里我只是本身好理解),那么上面的线程转换图就转变成了下面这样(参考《Java并发编程的艺术》中的线程状态图):安全
关于线程状态转换的例子,能够经过下面的代码加深理解并发
public class Test { public static void main(String[] args) { Test test = new Test(); // 1.NEW状态 Thread thread = new Thread(() -> { // 3.进行test对象锁的争夺,若抢到锁则继续执行,不然进入BLOCKED状态监控该锁,从新得到后进入RUNNABLE synchronized (test) { try { // 4.进入TIMED_WAITING状态,100ms后从新进入RUNNABLE状态争夺时间片 Thread.sleep(100); // 5.从新得到时间片以后,进入WAITING状态 test.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 6.正常run()方法执行完毕后线程结束,进入TERMINATED }); // 2.调用start()方法,线程进入RUNNABLE状态 thread.start(); }
}
注:代码执行的顺序为注释的序号
在上面的例子中咱们看到线程的run方法正常执行完毕以后线程就正常死亡进入TERMINATED状态了,那么若是咱们有中途中止线程的需求,咱们应该如何正确的结束一个线程呢?spa
public static void main(String[] args) { Thread thread = new Thread(() -> { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); // 这里的return是必须的,缘由后面说明 return; } System.err.println("thread interrupt test..."); }); thread.start(); thread.interrupt(); System.out.println("main thread end..."); }
// 结果图:异常后面的语句不会打印
这里关于线程中的打断标识变量(以后以interrupt称)须要说明的是,在特定的状况下其状态会被重置。
一、线程内部在catch了异常了以后interrupt的状态会被重置为false。
二、线程调用了Thread.interrupted()方法以后,interrupt的状态会被重置为false。若是须要判断线程是否中断的话可使用对象方法isInterrupted(),此方法不会重置。
因此在刚才的代码中须要加入return来结束线程,不然的话线程仍是会继续往下执行,以下图
使用isInterrupted()实现:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
int k = 0;
while (k++ < 10) {
System.out.println("do something..." + k);
}
}
System.err.println("thread end...");
});
thread.start();
Thread.sleep(1);
// 主线程流程执行完了,须要中止线程
thread.interrupt();
}
public class Test { public static volatile boolean interrupted = false; public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { while (!interrupted) { int k = 0; while (k++ < 10) { if (interrupted) { System.err.println("thread invoke end...."); return; } System.out.println("do something..." + k); } } System.err.println("thread end..."); }); thread.start(); Thread.sleep(1); // 主线程流程执行完了,须要中止线程 interrupted = true; } }
// 结果图
在线程提供的方法中还有一个方法能够强制关闭线程——stop()。这个方法能够说是至关的霸道,给人一种“我无论,我就是要你如今马上死亡(指线程)”的感受,而且其还会释放线程全部的锁资源,这样可能会致使出现数据不一致从而出现线程不安全的状况,以下面例子。线程
public class Test { public static volatile boolean flag = false; public int state = 0; public static void main(String[] args) throws InterruptedException { Test test = new Test(); Thread thread = new Thread(() -> { synchronized (test) { try { test.state = 1; Thread.sleep(100); if (flag) { test.state = 2; } System.err.println("thread execute finished..."); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); Thread.sleep(1); thread.stop(); flag = true; System.out.println("state状态:" + test.state); } }
// 在这段代码中,进入线程时默认将state赋为1,接着过一段时间后若是触发了特定条件则把state赋为2,可是在特定条件触发以前,线程就被终止掉了,这个特定条件虽然符合但却没办法执行,从而致使数据的不一致。
// 结果图![]()
因此,咱们应该采用上面两种正确的方式而不是stop()来停止线程。此外,stop()方法若在线程start()以前执行,那么在线程启动的时候就会当即死亡。
如有不对之处,望各位不吝指教(反正免费,对吧)。code
原文出处:https://www.cnblogs.com/zhangweicheng/p/11695849.htmlhtm