线程中断我们已经直到可以使用 interrupt() 方法,但是你必须要持有 Thread 对象,但是新的并发库中似乎在避免直接对 Thread 对象的直接操作,尽量使用 Executor 来执行所有的请求。如果你在 ExecutorService 上调用 shutdownNow() .那么它将发送一个 interrupt() 调用给它启动的所有线程。如果只是调用 shutdown() ,则不会发送中断。如果只是向中断某一个任务呢。如果使用ExcecutorService那么我们通过 submit() 来启动任务而不是通过 execut() 来启动任务,这样我们可持有该任务的上下文。 submit() 将返回一个泛型的 Future<?> 对象。持有这个关键字的对象的主要目的即可以接收 call() 方法的返回值,通过 get() 方法,也可以调用其 cancel() 方法,来中断某个特定的任务。。

A Future represents the result of an asynchronous computation. Future 表示异步计算的结果
Methods are provided to check if the computation is complete,to wait for its completion, and to retrieve the result of the computation.
它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果
The result can only be retrieved using method get when the computation has completed,
blocking if necessary until it is ready. Cancellation is performed by the cancel method.
计算完成后只能使用get方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由cancel方法来执行
Additional methods are provided to determine if the task completed normally or was cancelled. Once a computation has completed, the computation cannot be cancelled.
还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算
If you would like to use a Future for the sake of cancellability but not provide a usable result,
you can declare types of the form Future<?> and return null as a result of the underlying task.
Sample Usage (Note that the following classes are all made-up.)
如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。

cancle()api

boolean cancel(boolean mayInterruptIfRunning)
Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.
After this method returns, subsequent calls to isDone will always return true. Subsequent calls to isCancelled will always return true if this method returned true.
Parameters:
mayInterruptIfRunning - true if the thread executing this task should be interrupted; otherwise, in-progress tasks are allowed to complete
Returns:
false if the task could not be cancelled, typically because it has already completed normally; true otherwise
试图取消对此任务的执行。如果任务已完成、或已取消,或者由于某些其他原因而无法取消,则此尝试将失败。当调用 cancel 时,如果调用成功,而此任务尚未启动,则此任务将永不运行。如果任务已经启动,则 mayInterruptIfRunning 参数确定是否应该以试图停止任务的方式来中断执行此任务的线程。
此方法返回后,对 isDone() 的后续调用将始终返回 true。如果此方法返回 true,则对 isCancelled() 的后续调用将始终返回 true。
参数:
mayInterruptIfRunning - 如果应该中断执行此任务的线程,则为 true;否则允许正在运行的任务运行完成
返回:
如果无法取消任务,则返回 false,这通常是由于它已经正常完成;否则返回 true

阻塞的种类:

1、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
2、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
3、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

这个例子展示了几种不同的阻塞

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; /**
* Created by huaox on 2017/4/20.
*
*/ class SleepBlock implements Runnable{ @Override
public void run() {
try {
TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {
System.out.println("InterruptedException by sleep()");
}
System.out.println("Exiting SleepBlocked.run()");
}
} class IOBlock implements Runnable{
private InputStream inputStream; public IOBlock(InputStream inputStream) {
this.inputStream = inputStream;
} @Override
public void run() {
try {
System.out.println("Waiting for read(): ");
inputStream.read();
} catch (IOException e) {
if(Thread.currentThread().isInterrupted()){
System.out.println("");
}else{
System.out.println("DON'T Interrupted from block IO");
throw new RuntimeException(e);
} }
System.out.println("Exiting IOBlocked.run()");
}
}
//同步阻塞
class SynchronizedBlock implements Runnable{
synchronized void f(){ //永远不释放锁
while (true)
Thread.yield();
} public SynchronizedBlock() {
new Thread(){
@Override
public void run() {
f();
}
}.start();
} @Override
public void run() {
System.out.println("outer thread trying to call f()");
f();
System.out.println("Exiting SynchronizedBlock.run()");
}
} public class Interrupting {
private static ExecutorService executorService = Executors.newCachedThreadPool();
static void test(Runnable runnable) throws InterruptedException{
Future<?> future = executorService.submit(runnable);
TimeUnit.MILLISECONDS.sleep(100);
System.out.println("interrupting "+runnable.getClass().getName());
future.cancel(true);
System.out.println("interrupt sent to "+runnable.getClass().getName());
} public static void main(String[] args) throws InterruptedException {
test(new SleepBlock());
test(new IOBlock(System.in));
test(new SynchronizedBlock());
TimeUnit.SECONDS.sleep(3);
/* System.out.println("Aborting with System.exit(0)");
System.exit(0);*/
}
}

下面分别测试SleepBlock,IOBlock,SynchronizedBlock。运行结果

SleepBlock:可中断阻塞

interrupting SleepBlock
InterruptedException by sleep()
Exiting SleepBlocked.run()
interrupt sent to SleepBlock
Aborting with System.exit(0) Process finished with exit code 0

IOBlock:不可中断阻塞

Waiting for read():
interrupting IOBlock
interrupt sent to IOBlock
Aborting with System.exit(0) Process finished with exit code 0

SynchronizedBlock:不可中断阻塞

outer thread trying to call f()
interrupting SynchronizedBlock
interrupt sent to SynchronizedBlock
Aborting with System.exit(0) Process finished with exit code 0

从输出中可以看到,你能够中断对sleep()的调用,(或者任何要求抛出InterrptedException的调用)。但是,你不能中断正在视图获取synvhronized锁或者视图执行I/O操作的线程。但是对于IO。可以使用一个比较笨拙的方法。即关闭任务在其发生阻塞的底层资源。

import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; /**
* Created by huaox on 2017/4/20.
*
*/
public class CloseResource {
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
ServerSocket serverSocket = new ServerSocket(8888);
InputStream socketInput = new Socket("localhost",8888).getInputStream();
executorService.execute(new IOBlock(socketInput));
//executorService.execute(new IOBlock(System.in)); TimeUnit.MILLISECONDS.sleep(100);
System.out.println("shutting down all thread");
executorService.shutdownNow();
TimeUnit.SECONDS.sleep(1);
System.out.println("Closing "+ serverSocket.getClass().getName());
serverSocket.close(); /* TimeUnit.SECONDS.sleep(1);
System.out.println("Closing "+ System.in.getClass().getName());
System.in.close();*/
}
}

输出结果:对于serverSocket.可以关闭底层资源关闭

Waiting for read():
shutting down all thread
Closing java.net.ServerSocket
InterruptedException by block IO
Exiting IOBlocked.run()
Closing java.io.BufferedInputStream Process finished with exit code 0

程序正常终止,小红点变灰。如果对于文件IO。

import java.io.File;
import java.io.FileInputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; /**
* Created by huaox on 2017/4/20.
*
*/
public class CloseResource {
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
FileInputStream fileInputStream = new FileInputStream(new File("D:\\soft\\CCleaner.exe"));
/*ServerSocket serverSocket = new ServerSocket(8888);
InputStream socketInput = new Socket("localhost",8888).getInputStream();*/
//executorService.execute(new IOBlock(socketInput));
//executorService.execute(new IOBlock(System.in));
executorService.execute(new IOBlock(fileInputStream)); TimeUnit.MILLISECONDS.sleep(100);
System.out.println("shutting down all thread");
executorService.shutdownNow();
/* TimeUnit.SECONDS.sleep(1);
System.out.println("Closing "+ serverSocket.getClass().getName());
serverSocket.close();*/ TimeUnit.SECONDS.sleep(1);
System.out.println("Closing "+ fileInputStream.getClass().getName());
System.in.close();
}
}

输出结果:

Waiting for read():
Exiting IOBlocked.run()
shutting down all thread
Closing java.io.FileInputStream Process finished with exit code 0

也是可以关闭的。但我们应该用NIO更好的进行控制。

/**
* Created by huaox on 2017/4/20.
*
*/
class NIOBlock implements Runnable{
private final SocketChannel socketChannel; public NIOBlock( SocketChannel socketChannel) {
this.socketChannel = socketChannel;
} @Override
public void run() {
try {
System.out.println("Waiting for read(): "+this);
socketChannel.read(ByteBuffer.allocate(1));
}catch (ClosedByInterruptException e) {
System.out.println("ClosedByInterruptException");
}catch (AsynchronousCloseException e){
System.out.println("AsynchronousCloseException");
}catch (IOException e){
System.out.println("IOException");
}
System.out.println("Exiting NIOBlocked.run() "+this);
}
}
public class CloseResource { public static void main(String[] args) throws Exception {
testNIO();
} static void testNIO() throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
ServerSocket serverSocket = new ServerSocket(8888);
InetSocketAddress inetSocketAddress = new InetSocketAddress("localhost", 8888);
SocketChannel socketChannel1 = SocketChannel.open(inetSocketAddress);
SocketChannel socketChannel2 = SocketChannel.open(inetSocketAddress); Future<?> future = executorService.submit(new NIOBlock(socketChannel1));
executorService.execute(new NIOBlock(socketChannel2));
executorService.shutdown();
TimeUnit.SECONDS.sleep(1);
future.cancel(true);
TimeUnit.SECONDS.sleep(1);
socketChannel2.close();
}
}

输出结果:

Waiting for read(): NIOBlock@5cb03462
Waiting for read(): NIOBlock@6b033b12
ClosedByInterruptException            //对应submit()提交后调用Future的cancle(true)方法。
Exiting NIOBlocked.run() NIOBlock@5cb03462
AsynchronousCloseException 对用execute()提交后调用关闭系统底层资源的close()方法
Exiting NIOBlocked.run() NIOBlock@6b033b12 Process finished with exit code 0

对于 Channel ,如果通过 submit() 提交,那么可以使用 Future 的 cancel(true) 方法关闭,得到的异常是

ClosedByInterruptException 。如果是通过 execute() 提交,那么只能使用资源的 close() 方法进行关闭,得到的异常是 AsynchronousCloseException .

所以综上:我们最好使用 ExecutorService 的  Future<?> submit(Runnable task); 并且使用NIO.

就像前面你在不可中断I/O中或者等待同步锁中所观察到的那样,无论任何时刻,只要任务以不可中断的方式被阻塞,那么都有潜在的会锁住程序的可能,但是我们直到,在JDK5中,添加以了个特性。

即在 ReentrantLock 上阻塞的任务具备可以被中断的能力。这与 synchronized 方法或者临界区上阻塞的任务完全不同。

例子如下:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* Created by huaox on 2017/4/20.
*
*/ class BlockedMutex{
private Lock lock = new ReentrantLock();
BlockedMutex() {
lock.lock();
}
void f(){
try {
lock.lockInterruptibly();//这个方法具有可被中断的能力
System.out.println("lock acquired in f()");
} catch (InterruptedException e) {
System.out.println("interrupted from lock acquisition in f()");
}
}
}
class Blocked2 implements Runnable{
BlockedMutex mutex = new BlockedMutex();
@Override
public void run() {
System.out.println("waiting for f() in BlockedMutex");
mutex.f();
System.out.println("broken out of mutex call");
}
}
public class Interrupting2 { public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Blocked2());
thread.start();
TimeUnit.SECONDS.sleep(1);
System.out.println("call thread.interrupt");
thread.interrupt();
}
}

输出结果:

waiting for f() in BlockedMutex
call thread.interrupt
interrupted from lock acquisition in f()
broken out of mutex call Process finished with exit code 0

可以看到使用 Lock 的 public void lockInterruptibly() throws InterruptedException 时其具有可被中断的能力

所以我们以后最好不要使用 synchronized 而使用Lock

java多线程基本概述(二十)——中断的更多相关文章

  1. JAVA之旅(二十八)——File概述,创建,删除,判断文件存在,创建文件夹,判断是否为文件/文件夹,获取信息,文件列表,文件过滤

    JAVA之旅(二十八)--File概述,创建,删除,判断文件存在,创建文件夹,判断是否为文件/文件夹,获取信息,文件列表,文件过滤 我们可以继续了,今天说下File 一.File概述 文件的操作是非常 ...

  2. JAVA之旅(二十二)——Map概述,子类对象特点,共性方法,keySet,entrySet,Map小练习

    JAVA之旅(二十二)--Map概述,子类对象特点,共性方法,keySet,entrySet,Map小练习 继续坚持下去吧,各位骚年们! 事实上,我们的数据结构,只剩下这个Map的知识点了,平时开发中 ...

  3. JAVA之旅(二十四)——I/O流,字符流,FileWriter,IOException,文件续写,FileReader,小练习

    JAVA之旅(二十四)--I/O流,字符流,FileWriter,IOException,文件续写,FileReader,小练习 JAVA之旅林林总总也是写了二十多篇了,我们今天终于是接触到了I/O了 ...

  4. “全栈2019”Java多线程第六章:中断线程interrupt()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  5. 【Java学习笔记之二十六】深入理解Java匿名内部类

    在[Java学习笔记之二十五]初步认知Java内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客.在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意 ...

  6. JAVA之旅(二十九)——文件递归,File结束练习,Properties,Properties存取配置文件,load,Properties的小练习

    JAVA之旅(二十九)--文件递归,File结束练习,Properties,Properties存取配置文件,load,Properties的小练习 我们继续学习File 一.文件递归 我们可以来实现 ...

  7. JAVA之旅(二十六)——装饰设计模式,继承和装饰的区别,LineNumberReader,自定义LineNumberReader,字节流读取操作,I/O复制图片

    JAVA之旅(二十六)--装饰设计模式,继承和装饰的区别,LineNumberReader,自定义LineNumberReader,字节流读取操作,I/O复制图片 一.装饰设计模式 其实我们自定义re ...

  8. JAVA之旅(二十五)——文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine

    JAVA之旅(二十五)--文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine 我们继续IO上个篇 ...

  9. JAVA之旅(二十)—HashSet,自定义存储对象,TreeSet,二叉树,实现Comparator方式排序,TreeSet小练习

    JAVA之旅(二十)-HashSet,自定义存储对象,TreeSet,二叉树,实现Comparator方式排序,TreeSet小练习 我们继续说一下集合框架 Set:元素是无序(存入和取出的顺序不一定 ...

  10. Java 设计模式系列(二十)状态模式

    Java 设计模式系列(二十)状态模式 状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式.状态模式允许一个对象在其内部状态改变的时候改 ...

随机推荐

  1. Alamofire源码解读系列(五)之结果封装(Result)

    本篇讲解Result的封装 前言 有时候,我们会根据现实中的事物来对程序中的某个业务关系进行抽象,这句话很难理解.在Alamofire中,使用Response来描述请求后的结果.我们都知道Alamof ...

  2. apicloud上传图片

    //定义api $("#photo").change(function(){ //获取图片 api.getPicture({ sourceType: 'library', enco ...

  3. .NET 知识整理笔记

    本文纯属自己理解着写的,如果有什么错误或者不全面希望读者能够加以补充!~ 1.Web.Config配置文件的节点操作. 在Web.Config中写入. <configuration> &l ...

  4. (十) Jquery的基本使用

    一.引入 注意:如果在index.js中有使用到JQuery.js 那么JQuery.js文件必须比index.js文件先引入,否则index.js文件中不能使用JQuery.js. <scri ...

  5. SQLSERVER2008 错误18456

    我遇到的问题,已经解决,如果你遇到不能解决可以咨询我 1.以windows验证模式进入数据库管理器. 第二步:右击sa,选择属性: 在常规选项卡中,重新填写密码和确认密码(改成个好记的).把强制实施密 ...

  6. python--对函数的理解

    函数的定义 def functionname(arg): Suite Return [expression] 1.def 定义函数时的关键字 2.functionname 函数名 3.arg函数的参数 ...

  7. @Autowired 注释对在哪里和如何完成自动连接提供了更多的细微的控制。

    1.@Autowired 可以用在多个地方,在 setter 方法上,属性上 或者 带有多个参数的任意方法上. Setter 方法中的 @Autowired. 当 Spring遇到一个在 setter ...

  8. LINQ笔记

    LINQ概述 语言集成查询(Language intergrated Query,LINQ)在C#编程语言中集成了查询语法. 可以使用相同的语法访问不同的数据源 提供了不同数据源的抽象层,所有可以使用 ...

  9. Backbone.js中的where和findWhere

    小编的公司框架用的MVC框架依旧是Backbone.js,老大说框架不重要,重要的是框架的编程思想.于是乎,小编从头开始学习Backbone.走马观花似的看了下API文档,撸起袖子就是干.但是碰到一个 ...

  10. oracle图形界面乱码

    oracle界面乱码解决方案 在Linux的中文操作系统下使用xmanager进行Oracle进行安装的时候,可能出现乱码界面,可以通过以下方法进行解决 1 修改环境属性  vi /etc/sysco ...