Java多线程 之 终结任务(十一)
来源:互联网 发布:江恩计算器算法 编辑:程序博客网 时间:2024/04/30 06:10
ExecutorService.awaitTermination()等待每个任务结束,如果所有的任务在超时时间到达之前都结束了,则返回true,如果没有全部结束则返回false。这会导致每个任务都退出其run方法,并因此作为任务而终止。
这里要讨论的主题是:如果一个任务处于阻塞状态如何终止它?也就是说在run方法的中间如何终止它?中断被阻塞的任务可能需要清理资源。为了能够在run方法的中间终止任务时,返回众所周知的良好状态,需要仔细编写catch子句以正确清除所有事物。
1.线程的状态
(1)新建(new):线程只会在很短的时间内处于这个状态,并会立即转入就绪态。处于新建状态表示线程已经获取到了必要的系统资源,并执行了初始化。
(2)就绪态(Runnable):线程在这个状态下,只要调度器分配给它CPU时间片就可以执行。
(3)阻塞态(Blocked):线程能够执行,但是被某些条件阻止它的执行。处于阻塞态的线程,调度器会忽略阻塞态线程,不会分配给它CPU时间片。
(4)死亡态(Dead):处于死亡或终止状态的线程是不能被调度的,而且再也不会被分配时间片。线程进入死亡态或终止态的方式通常是run执行结束返回,当然也有可能是被直接中断。
2.造成线程阻塞的原因
(1)sleep,任务进入休眠状态,在给定的时间内不会运行。
(2)wait,直到得到了notify或者notifyAll(在JDK5之后是,signal或者signalAll)消息才会被转入就绪态。
(3)IO,等待某个IO完成。
(4)锁,当试图获取某个对象的锁时,这个对象上的锁已经被其他线程获取,则这个线程必须阻塞。
3.关于中断
如果线程A调用了sleep、wait、join,则线程A会进入阻塞状态,而且这些阻塞都是可以被中断的。当线程B调用A.interrupt()时,A线程可以被中断,也就是说退出执行,并设置线程A的中断状态为true。如果在A线程上编写了catch(InterruptedException e)则会捕获该异常,并置该中断状态为false。如果没有捕获InterruptedException异常,而是调用了Thread.interrupted或者isInterrupted()。这时先看下这两个方法的区别。
相同点:都是返回当前线程的中断状态。如果当前线程已经中断,则返回 true;否则返回 false。
Thread.interrupted()会清除线程的中断状态,即由true变成false;而isInterrupted()不会清除线程的中断状态,一直都是true。
package org.fan.learn.thread.share;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;import java.util.concurrent.TimeUnit;/** * Created by fan on 2016/6/29. */class SleeperTask implements Runnable { public void run() { try { TimeUnit.SECONDS.sleep(100); } catch (InterruptedException e) { System.out.println("isInterrupted: " + Thread.currentThread().isInterrupted()); System.out.println("Thread.interrupted: " + Thread.interrupted()); } System.out.println("Sleeper Task exit!"); }}public class InterruptTest { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); Future<?> f = executorService.submit(new SleeperTask()); TimeUnit.MILLISECONDS.sleep(100); //这句挺重要,为了让SleeperTask先运行。 executorService.shutdownNow(); //f.cancel(true); System.out.println("main exit!"); }}
执行结果如下:
main exit!
isInterrupted: false
Thread.interrupted: false
Sleeper Task exit!
从上面代码的执行结果可以看出,抛出异常之后,会清除线程的中断状态。
package org.fan.learn.thread.share;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;import java.util.concurrent.TimeUnit;/** * Created by fan on 2016/6/29. */class SleeperTask implements Runnable { public void run() { while (true) { if (Thread.currentThread().isInterrupted()) { System.out.println("isInterrupted: " + Thread.currentThread().isInterrupted()); } if (Thread.interrupted()) { System.out.println("Thread.interrupted: " + Thread.interrupted()); break; } } System.out.println("Sleeper Task exit!"); }}public class InterruptTest { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); Future<?> f = executorService.submit(new SleeperTask()); TimeUnit.MILLISECONDS.sleep(100);//这句挺重要,为了让SleeperTask先运行。 executorService.shutdownNow(); //f.cancel(true); System.out.println("main exit!"); }}
这个代码一次执行结果如下:
isInterrupted: true
Thread.interrupted: false
Sleeper Task exit!
main exit!
其他执行结果如下:
main exit!
isInterrupted: true
Thread.interrupted: false
Sleeper Task exit!
其他结果:
main exit!
Thread.interrupted: false
Sleeper Task exit!
从上面的输出可以看出,isInterrupted()不会清除中断状态,而Thread.interrupted()方法会清除中断状态。
注意:
上面的两个例子中,都有两种方式向线程发送中断信号,其中一种方式是使用Future,一种是使用ExecutorService的shutdownNow方法。这两者的区别如下:
如果使用ExecutorService.shutdownNow()方法会发送一个interrupt()调用给它启动的所有线程。而使用Future的cancel()方法则只是向某个特定的线程发送interrupt()调用。
shutdownNow与shutdown的区别:
shutdown不会发送interrupt调用。
强调:
sleep、wait、join造成的阻塞都是可以中断的;而IO、锁造成的阻塞是不可中断的。
对于不可中断的IO、锁阻塞,如果非要中断,可以通过关闭所占用的资源来实现。如关闭阻塞的IO。
synchronized方法或者临界区不能被中断,但是在ReentrantLock上阻塞的任务却可以被中断。
一个任务能够调用在同一个对象中的其他的synchronized方法,因为这个任务已经持有锁了。这一点其实已经在前面阐述过,其实现原理就是一个计数器。详见: Java多线程 之 访问共享资源synchronized、lock(七)。
当你在线程上调用interrupt()时,中断发生的唯一时刻是:在任务要进入到阻塞操作或者已经在阻塞操作内部时。如果只能通过在阻塞调用上抛出异常来退出,那就无法总是可以离开run方法。
要做好系统资源的清理工作,需要写好try-finally语句。
- Java多线程 之 终结任务(十一)
- Java多线程之终结任务
- java多线程系列----------- 终结任务(一)
- java多线程系列----------- 终结任务(二)
- Java并发之终结任务
- java 多线程 终结任务 装饰性花园
- Java多线程实践之—终结
- java 多线程 终结任务 关于I/O和synchronized
- Java基础之十一:多线程
- (十一)java多线程之Phaser
- java Thread学习(终结任务)
- java中的多线程终结
- (39)21.4 终结任务---Java编程思想之并发笔记
- Java程序员从笨鸟到菜鸟之(十一)多线程讲解
- Java程序员从笨鸟到菜鸟之(十一)多线程讲解
- Java程序员从笨鸟到菜鸟之(十一)多线程讲解
- Java程序员从笨鸟到菜鸟之(十一)多线程讲解
- Java程序员从笨鸟到菜鸟之(十一)多线程讲解
- 虚拟现实-VR-UE4-创建C++版工程
- 安卓报错
- windows命令操作
- Java集合类性能分析
- 写给程序猿的把妹指南
- Java多线程 之 终结任务(十一)
- iOS根据接口生成二维码
- Unresolved inclusion
- Java事务--概述
- 欧几里得算法求n个数据的最大公约数
- 坑爹的碰撞检测
- 将项目发布到私服Nexus
- HIVE原生和复合类型的数据加载和使用
- 【黑马Android】(18)Servlet/ServletConfig/ServletContext