java多线程基本概述(二十)——中断
线程中断我们已经直到可以使用 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多线程基本概述(二十)——中断的更多相关文章
- JAVA之旅(二十八)——File概述,创建,删除,判断文件存在,创建文件夹,判断是否为文件/文件夹,获取信息,文件列表,文件过滤
JAVA之旅(二十八)--File概述,创建,删除,判断文件存在,创建文件夹,判断是否为文件/文件夹,获取信息,文件列表,文件过滤 我们可以继续了,今天说下File 一.File概述 文件的操作是非常 ...
- JAVA之旅(二十二)——Map概述,子类对象特点,共性方法,keySet,entrySet,Map小练习
JAVA之旅(二十二)--Map概述,子类对象特点,共性方法,keySet,entrySet,Map小练习 继续坚持下去吧,各位骚年们! 事实上,我们的数据结构,只剩下这个Map的知识点了,平时开发中 ...
- JAVA之旅(二十四)——I/O流,字符流,FileWriter,IOException,文件续写,FileReader,小练习
JAVA之旅(二十四)--I/O流,字符流,FileWriter,IOException,文件续写,FileReader,小练习 JAVA之旅林林总总也是写了二十多篇了,我们今天终于是接触到了I/O了 ...
- “全栈2019”Java多线程第六章:中断线程interrupt()方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- 【Java学习笔记之二十六】深入理解Java匿名内部类
在[Java学习笔记之二十五]初步认知Java内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客.在这篇博客中你可以了解到匿名内部类的使用.匿名内部类要注意 ...
- JAVA之旅(二十九)——文件递归,File结束练习,Properties,Properties存取配置文件,load,Properties的小练习
JAVA之旅(二十九)--文件递归,File结束练习,Properties,Properties存取配置文件,load,Properties的小练习 我们继续学习File 一.文件递归 我们可以来实现 ...
- JAVA之旅(二十六)——装饰设计模式,继承和装饰的区别,LineNumberReader,自定义LineNumberReader,字节流读取操作,I/O复制图片
JAVA之旅(二十六)--装饰设计模式,继承和装饰的区别,LineNumberReader,自定义LineNumberReader,字节流读取操作,I/O复制图片 一.装饰设计模式 其实我们自定义re ...
- JAVA之旅(二十五)——文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine
JAVA之旅(二十五)--文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine 我们继续IO上个篇 ...
- JAVA之旅(二十)—HashSet,自定义存储对象,TreeSet,二叉树,实现Comparator方式排序,TreeSet小练习
JAVA之旅(二十)-HashSet,自定义存储对象,TreeSet,二叉树,实现Comparator方式排序,TreeSet小练习 我们继续说一下集合框架 Set:元素是无序(存入和取出的顺序不一定 ...
- Java 设计模式系列(二十)状态模式
Java 设计模式系列(二十)状态模式 状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式.状态模式允许一个对象在其内部状态改变的时候改 ...
随机推荐
- 关于js模拟c#的Delegate(委托)实现
这是我的第一篇博文,想来讲一讲js的函数.我的标题是js模拟c#的Delegate. 一.什么是Delegate(委托) 在jquery中有delegate函数,作用是将某个dom元素的标签的事件委托 ...
- 2751: [HAOI2012]容易题(easy)
2751: [HAOI2012]容易题(easy) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1087 Solved: 477[Submit][ ...
- 1774: [Usaco2009 Dec]Toll 过路费
1774: [Usaco2009 Dec]Toll 过路费 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 263 Solved: 154[Submit ...
- 2017年你需要一个VPN
还有29天就2017年了,今天跟同事还在讨论这个问题,2016你都做了些什么事情?2017你有什么计划和期待?有空我们一起来聊聊,今天我们就先来聊聊VPN. 记得2016年11月初的时候,我写过一篇文 ...
- HibernateSessionFactory类的主要方法
package com.app.www.hibernate; import java.sql.SQLException; import org.hibernate.HibernateException ...
- JDBC(上)
1. 课程回顾 mysql加强 1)数据约束(表约束) 默认值: default 默认值 非空: not null 唯一: unique 主键: primary key (非空+唯一) 自增长: ...
- 内网转发ngrok的使用
1.下载解压ngrok:https://ngrok.com/download 2.执行ngrok会打开控制台 3.输入命令,开始映射本地的8080端口 ngork http 8080 控制台会返回一个 ...
- Tomcat+Eclipse乱码问题解决方法
概述 乱码问题是大家在日常开发过程中经常会遇到的问题,由于各自环境的不同,解决起来也费时费力,本文主要介绍一般性乱码问题的解决方法与步骤,开发工具采用Eclipse+Tomcat,统一设置项目编码UT ...
- 【Java基础】通过getResourceAsStream() 加载资源文件
Class.getResourceAsStream(String path) path不以"/"开头时,默认是从当前类所在的包下面获取资源 path以"/"开头 ...
- 于普通用户启动UAC问题
在VS中设置UAC级别操作如下: 项目属性-配置属性-连接器-清单文件 1.UAC执行级别: aslnvoker: 权限级别最低,不需要管理员身份. highestAvailable:获取最高权限执行 ...