初阶并发编辑之——线程状态与线程中断
来源:互联网 发布:欧洲卡车模拟2 mac 编辑:程序博客网 时间:2024/06/12 04:38
//在阻塞中终结
线程的六种状态(网上有说五种,Thinking in Java中说四种,我这里以jdk1.8的API为主,jdk1.5开始都是6种):
1)新建NEW
当线程Thread()被创建后,调用start()方法之前,尚未启动的线程处于此状态。
2)可运行RUNNABLE
线程调用start(),并占有CUP时间,在Java虚拟机中执行的线程处于此状态,但它可能正在等待来自操作系统(例如处理器)的其他资源。
3)阻塞BLOCKED
一个线程的线程状态阻塞等待监视器锁定。处于阻塞状态的线程正在等待监视器锁定进入同步块/方法,或者在调用Object.wait后重新输入同步的块/方法。
4)等待WAITING
等待状态的线程正在等待另一个线程执行特定的动作。 例如,已经在对象上调用Object.wait()线程正在等待另一个线程调用该对象上Object.notify() Object.notifyAll()或。 调用Thread.join()的线程正在等待指定的线程终止。
5)计时等待TIMED_WAITING
具有指定等待时间的某一等待线程的线程状态。
6)死亡TERMINATED
已终止线程的线程状态。线程已运行完毕。它的run()方法已正常结束或通过抛出异常而结束。线程的终止run()方法,线程结束。
现在我们逐一分析各个状态:
当新建一个线程时,它已经分配了必须的系统资源,并执行了初始化,已经有资格获取cpu时间,就好比排队上厕所,你可以有资格抢占厕所。一旦调度器调用就进入运行状态。进入可运行状态的线程可能正在运行中,也可能没有运行,取决于操作系统给线程提供的时间。线程开始运行,它不必保持运行。运行中的线程被中断目的就是让其他线程获得机会。比如正在运行的线程调用yield方法,或者被堵塞(一般如IO中等待输入是堵塞)就会让出cpu,就好像你进去厕所后呆一会又出来让别人先用。被堵塞线程和等待线程都是线程从运行到停止运行,都暂时停止线程的执行。不同的是线程被堵塞是被动堵塞,在持有对象的同步块或者方法中(比如synchronized块或者方法,非java.util.concurrent库中的锁)已经有线程抢占,就会进入堵塞状态。而等待线程是主动的,在满足条件后再去运行,操作系统中知道什么时候停止等待,就比如main主程序中在t1和t2的start()方法中添加t1.join(),就会让main主线程进入等待,当t1线程运行完毕再激活main主线程去执行t2.start()。至于计时等待就是在等待的基础上添加等待的时间。比如方法sleep(100)和其他限制时间的方法。而被终止的线程进入死亡状态如下两个原因:run方法正常退出而自然死亡。因为一个没有捕获的异常而意外死亡。
各状态的转换如下图:
中断
Thread类的静态方法interrupt()方法可以中断被阻塞的任务,这个方法将改变中断状态。如果一个线程已经被堵塞,或者试图执行堵塞操作,那么设置这个中断状态将会抛出一个InterrupttedException,当抛出该异常时或者调用Thread.interrupted()方法时(注意这里,是interrupted(),不是interrupt()方法,api对这个方法的解释是:测试当前线程是否中断。 该方法可以清除线程的中断状态 。换句话说,如果这个方法被连续调用两次,那么第二个调用将返回false(除非当前线程再次中断,在第一个调用已经清除其中断状态之后,在第二个调用之前已经检查过)。忽略线程中断,因为线程在中断时不存在将被该方法返回false所反映。),中断状态会复位,变会原来的状态。interrupt()方法必须持有Thread对象,但是也可以使用Executor中方法shutdownNow()将发送一个interrupt()给它控制的所有线程。现在我们看一个用10个线程将1000递减的代码实例:
class whileGo implements Runnable{ private static volatile boolean isGo; public int id; public volatile static int value = 1000; public static int getValue(){ return value; } public static void Stop(){ isGo = false; } public whileGo(int i){ isGo = true; this.id = i; } @Override public void run() { // TODO Auto-generated method stub //System.out.println("whileGo----------interruptState: "+Thread.currentThread(). isInterrupted()); try { while(true){ synchronized(whileGo.class){ --value; System.out.println("whileGo"+this.id+" "+getValue()); } TimeUnit.MILLISECONDS.sleep(100); /*if(Thread.interrupted()){ System.out.println(Thread.interrupted()); //Stop(); }*/ } } catch (InterruptedException e) { System.out.println("捕获线程"+this.id+"异常InterruptedException并中断该线程!"); } }}public class InterruptTest1 { public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); for(int i=0;i<10;i++){ exec.execute(new whileGo(i)); } try { TimeUnit.MILLISECONDS.sleep(200); //将主线程休眠0.2秒,再执行终止操作。 exec.shutdownNow(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}输出结果如下:whileGo0 999whileGo8 998whileGo7 997whileGo6 996whileGo5 995whileGo4 994whileGo3 993whileGo2 992whileGo1 991whileGo9 990whileGo5 989whileGo0 988whileGo4 987whileGo9 986whileGo1 985whileGo8 984whileGo3 983whileGo7 982whileGo6 981whileGo2 980whileGo3 979whileGo0 978whileGo5 977whileGo4 976whileGo8 975whileGo9 974whileGo1 973whileGo7 972捕获线程9异常InterruptedException并中断该线程!捕获线程0异常InterruptedException并中断该线程!捕获线程3异常InterruptedException并中断该线程!捕获线程8异常InterruptedException并中断该线程!捕获线程1异常InterruptedException并中断该线程!捕获线程4异常InterruptedException并中断该线程!捕获线程7异常InterruptedException并中断该线程!捕获线程6异常InterruptedException并中断该线程!捕获线程2异常InterruptedException并中断该线程!捕获线程5异常InterruptedException并中断该线程!`
再编写这个代码的时候我遇到了这几个问题,可以和大家分享以下:
第一:在run()方法中的同步块synchronized中的()我刚开始是写this的,发现value值被没有被锁住。后来我才发现,我设置value为static,那么他就应该是属于类whileGo的,对象锁是所不主的,应该锁的是类。总结一下就是你在同步块中锁的东西属于什么就设置什么锁,锁的是对象中的状态就锁对象,锁的是类中 的静态变量就锁类。
第二:本来方法getValue()我是加锁的,但是发现唯一调用到该方法的代码已经在锁中了,加锁就毫无意义了。
第三:大家看到我下面注释的代码部分,本来我的理解是在主线程中执行器将各个线程的中断状态改变为ture,然后在run中的while循环中用interrupted()判断中断状态再去stop任务,结果线程一直无法中断。输出Thread.currentThread().interrupted()发现一直是flase。原来当抛出异常interruptException或者调用interrupted()方法时中断状态会复位回到false。正确的思路应该时将try-catch语句与中断机制结合,再抛出interruptException,注意的是while循环一定要在try中不然无法中断。
//if(Thread.interrupted()){// Stop();// }
不过interrupt()不可中断I/O和再synchronized块上的等待。在I/O中调用interrupt()不会抛出interruptException异常。
- 初阶并发编辑之——线程状态与线程中断
- JAVA并发编程(四)——线程状态与中断
- 《Java并发编程》之线程中断与终止线程运行
- 《Java并发编程》之线程中断与终止线程运行
- 初阶并发编辑之——基本的线程机制
- Java并发学习之三——线程的中断
- Java并发之线程中断
- Java并发编程——线程中断
- Java并发——线程中断学习
- Java多线程与并发(四)之中断线程
- java并发——线程状态
- java线程——中断线程+线程状态+线程属性(优先级)
- 初阶并发编程之——运用wait()与notify()实现线程之间的协作
- Java并发编程基础构建模块(04)——线程阻塞与中断
- Java并发编程基础构建模块(04)——线程阻塞与中断
- Java并发学习之四——操作线程的中断机制
- Java 并发编程深入学习(四)——线程中断
- JAVA多线程之——线程中断
- 框架结合之Spring和struts2
- lambda表达式10个示例
- Linux系统测试端口连通性的方法
- 菜鸟编程 指针初步
- golang语言并发与并行——goroutine和channel的详细理解(三)
- 初阶并发编辑之——线程状态与线程中断
- 689. Maximum Sum of 3 Non-Overlapping Subarrays
- 刷新加载+异步线程
- Maven的安装和配置(Windows)
- 树和森林
- bzoj1001 [BeiJing2006]狼抓兔子
- 正则表达式全部符号解释
- JavaWeb学习笔记-servlet-03-HttpServlet
- 二、jena解析关于基因的go.owl文件(创建、新增类、以及一些节点)