java并发编程(1)并发程序的取消于关闭
一、任务的取消于关闭
1、中断Thread
1.每个线程都有一个boolean类型的中断状态。true则是中断状态中
interrupt:发出中断请求;isInterrupt:返回中断状态;interrupted:清除中断状态
2.JVM中的阻塞方法会检查线程中断状态,其响应方法为:清除中断状态,抛出InterruptedException异常,表示阻塞操作被中断结束 ;但JVM不保证阻塞方法何时检测到线程的中断状态
3.中断的理解:不会真正的中断一个正在运行的线程,而只是发出请求,具体的中断由任务自己处理
通过中断来取消线程通常是最好的方法
public class PrimeProducer extends Thread {
private final BlockingQueue<BigInteger> queue;
PrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
public void run() {
try {
BigInteger p = BigInteger.ONE;
while (!Thread.currentThread().isInterrupted())
queue.put(p = p.nextProbablePrime());
} catch (InterruptedException consumed) {
/* Allow thread to exit */
//如果捕获到中断异常,则由线程自己退出
}
}
public void cancel() {
interrupt();
}
}
2、不可中断的阻塞的中断
如:Socket I/O操作,即使设置了中断请求,也不会中断,但是close 套接字,会使其抛出异常,达到中断效果;因此我们要重写中断方法
//自定义callable实现类
public abstract class SocketUsingTask <T> implements CancellableTask<T> {
private Socket socket; protected synchronized void setSocket(Socket s) {
socket = s;
}
//取消方法
public synchronized void cancel() {
try {
if (socket != null)
socket.close();
} catch (IOException ignored) {
}
}
//新建实例的方法
public RunnableFuture<T> newTask() {
return new FutureTask<T>(this) {
public boolean cancel(boolean mayInterruptIfRunning) {
try {
SocketUsingTask.this.cancel();
} finally {
return super.cancel(mayInterruptIfRunning);
}
}
};
}
} //自定义callable接口
interface CancellableTask <T> extends Callable<T> {
void cancel();
RunnableFuture<T> newTask();
}
//自定义 执行池
class CancellingExecutor extends ThreadPoolExecutor {
......
//通过改写newTaskFor 返回自己的Callable
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
if (callable instanceof CancellableTask)
return ((CancellableTask<T>) callable).newTask();
else
return super.newTaskFor(callable);
}
}
3、通过自定义取消计时任务
private static final ScheduledExecutorService cancelExec = newScheduledThreadPool(1);
/**
*
* @param r 任务
* @param timeout 超时时间
* @param unit TimeUnit
* @throws InterruptedException
*/
public static void timedRun(final Runnable r,long timeout, TimeUnit unit) throws InterruptedException {
class RethrowableTask implements Runnable {
//通过一个volatile变量,来存储线程是否异常
private volatile Throwable t;
public void run() {
try {
r.run();
} catch (Throwable t) {
this.t = t;
}
}
private void rethrow() {
if (t != null)
throw launderThrowable(t);
}
}
RethrowableTask task = new RethrowableTask();
final Thread taskThread = new Thread(task);
taskThread.start();
//延时timeout个unit单位后 执行线程中断
cancelExec.schedule(() -> taskThread.interrupt(), timeout, unit);
//无论如何都等待;如果线程不响应中断,那么通过join等待任务线程timeout时间后 不再等待,回到调用者线程
taskThread.join(unit.toMillis(timeout));
//如果 任务线程中有异常,则抛出
task.rethrow();
}
注意:依赖于join,任务超时join退出 和 任务正常join推出 无法进行判断
4、通过Futrue来实现取消计时任务
private static final ExecutorService taskExec = Executors.newCachedThreadPool();
public static void timedRun(Runnable r,long timeout, TimeUnit unit) throws InterruptedException {
Future<?> task = taskExec.submit(r);
try {
//通过Futrue.get(超时时间),捕获相应的异常来处理计时运行和取消任务
task.get(timeout, unit);
} catch (TimeoutException e) {
// task will be cancelled below
} catch (ExecutionException e) {
// exception thrown in task; rethrow
throw launderThrowable(e.getCause());
} finally {
// Harmless if task already completed
task.cancel(true); // interrupt if running
}
}
二、停止基于线程的服务
1.通常,服务不能直接中断,造成服务数据丢失
2.线程池服务也不能直接中断
1、日志服务
标准的生产者,消费者模式
public class LogService {
private final BlockingQueue<String> queue;
private final LoggerThread loggerThread;
private final PrintWriter writer;
private boolean isShutdown;
private int reservations;
public LogService(Writer writer) {
this.queue = new LinkedBlockingQueue<String>();
this.loggerThread = new LoggerThread();
this.writer = new PrintWriter(writer);
}
public void start() {
loggerThread.start();
}
public void stop() {
synchronized (this) {
isShutdown = true;
}
loggerThread.interrupt(); //发出中断
}
public void log(String msg) throws InterruptedException {
synchronized (this) {
if (isShutdown){
throw new IllegalStateException(/*...*/);
}
++reservations; //保存的正确的在队列中的日志数量
}
queue.put(msg); //将日志放入队列
}
private class LoggerThread extends Thread {
public void run() {
try {
while (true) {
try {
synchronized (LogService.this) {
if (isShutdown && reservations == 0) {
break;
}
}
String msg = queue.take();
synchronized (LogService.this) {
--reservations;
}
writer.println(msg);
} catch (InterruptedException e) { /* retry */
//捕获了中断请求,但为了将剩余日志输出,不做处理,直到计数器 == 0时,关闭
}
}
} finally {
writer.close();
}
}
}
}
2、ExecutorService中断
shutDown和shutDownNow
通常,将ExecetorService封装;如LogService,使其具有自己的生命周期方法
shutDownNow的局限性:不知道当前池中的线程状态,返回未开始的任务,但不能返回已开始未结束的任务
public class TrackingExecutor extends AbstractExecutorService {
private final ExecutorService exec;
private final Set<Runnable> tasksCancelledAtShutdown =
Collections.synchronizedSet(new HashSet<Runnable>());
public TrackingExecutor() {
exec = Executors.newSingleThreadExecutor();
}
/*public TrackingExecutor(ExecutorService exec) {
this.exec = exec;
}*/
public void shutdown() {
exec.shutdown();
}
public List<Runnable> shutdownNow() {
return exec.shutdownNow();
}
public boolean isShutdown() {
return exec.isShutdown();
}
public boolean isTerminated() {
return exec.isTerminated();
}
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
return exec.awaitTermination(timeout, unit);
}
public List<Runnable> getCancelledTasks() {
if (!exec.isTerminated())
throw new IllegalStateException(/*...*/);
return new ArrayList<Runnable>(tasksCancelledAtShutdown);
}
public void execute(final Runnable runnable) {
exec.execute(new Runnable() {
public void run() {
try {
runnable.run();
} finally {
if (isShutdown()
&& Thread.currentThread().isInterrupted())
tasksCancelledAtShutdown.add(runnable);
}
}
});
}
@Test
public void test() throws InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
TrackingExecutor trackingExecutor = new TrackingExecutor();
trackingExecutor.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
System.err.println("123123");
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); //设置状态 或继续抛,在execute中处理
e.printStackTrace();
} finally {
}
}
});
List<Runnable> runnables = trackingExecutor.shutdownNow();
trackingExecutor.awaitTermination(10,TimeUnit.SECONDS);
List<Runnable> cancelledTasks = trackingExecutor.getCancelledTasks();
System.err.println(cancelledTasks.size());
}
}
三、处理非正常线程终止
1.未捕获的Exception导致的线程终止
1.手动处理未捕获的异常
2.通过Thread的API UncaughExceptionHandler,能检测出某个线程又遇见未捕获而导致异常终止
注意:默认是将异常的的堆栈信息 输出到控制台;自定义的Handler:implements Thread.UncaughExceptionHandler覆写方法
可以为每个线程设置,也可以设置一个全局的ThreadGroup
Thread.setUncaughtExceptionHandler/Thread.setDefaultUncaughtExceptionHandler
2.JVM退出、守护线程等
java并发编程(1)并发程序的取消于关闭的更多相关文章
- <<java 并发编程>>第七章:取消和关闭
Java没有提供任何机制来安全地终止线程,虽然Thread.stop和suspend等方法提供了这样的机制,但是存在严重的缺陷,应该避免使用这些方法.但是Java提供了中断Interruption机制 ...
- Java并发编程:并发容器之ConcurrentHashMap(转载)
Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...
- Java并发编程:并发容器之ConcurrentHashMap
转载: Java并发编程:并发容器之ConcurrentHashMap JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的 ...
- Java并发编程:并发容器ConcurrentHashMap
Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...
- 【转】Java并发编程:并发容器之ConcurrentHashMap
JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都串行化了,这样保证了线程的安全性,所以这种方法的代价就是严重降低了 ...
- Java并发编程:并发容器之ConcurrentHashMap(转)
本文转自:http://www.cnblogs.com/dolphin0520/p/3932905.html Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载 ...
- 10、Java并发编程:并发容器之ConcurrentHashMap
Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...
- Java并发编程:并发容器之CopyOnWriteArrayList(转载)
Java并发编程:并发容器之CopyOnWriteArrayList(转载) 原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW ...
- Java并发编程:并发容器之CopyOnWriteArrayList
转载: Java并发编程:并发容器之CopyOnWriteArrayList Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个 ...
- 【Java并发编程】并发编程大合集-值得收藏
http://blog.csdn.net/ns_code/article/details/17539599这个博主的关于java并发编程系列很不错,值得收藏. 为了方便各位网友学习以及方便自己复习之用 ...
随机推荐
- C# 调用C++动态库注意事项
C# 调用C++动态库注意事项 最近项目上需要在C#中调用C++,期间遇到不少坑,总结如下: 1.in const char* 对应C#中string 或 IntPtr 2.out const ...
- NVIDIA GTC照片
这次的NVIDIA GPU Technology Conference 2014在美国San Jose(就是俗称的硅谷了)举办. 去美国的飞机上10个小时反正是睡不着,电影还是挺好看的. 美联航的早餐 ...
- python字符串的切片
# 字符串的切片 """ (5)字符串的切片 :切片就是截取字符串的意思 (1)语法 =>字符串[::] 完整格式:[开始索引:结束索引:间隔值 (2)[:结束索引 ...
- “全栈2019”Java第七十七章:抽象内部类与抽象静态内部类详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- bzoj1009GT考试
题目链接 没啥好说的,矩阵优化+$kmp$字符串匹配 上代码: /************************************************************** Prob ...
- UIView之setNeedsDisplay与drawRect 和 setNeedsLayout与layoutSubViews
1.UIView的setNeedsDisplay和setNeedsLayout方法 首先两个方法都是异步执行的.而setNeedsDisplay会调用自动调用drawRect方法,这样可以拿到 UI ...
- top 常用命令
参考文档: http://www.cnblogs.com/allen8807/archive/2010/11/10/1874001.html [root@linux ~]# top [-d] | to ...
- 针对myeclipse6.5无法自动生成toString方法
public void getToStringSTR(){ Field[] fs = this.getClass().getDeclaredFields(); for (int i = 0; i &l ...
- 对cors的理解
一.简介 CORS需要浏览器和服务器同时支持.目前,所有浏览器都支持该功能,IE浏览器不能低于IE10. 整个CORS通信过程,都是浏览器自动完成,不需要用户参与.对于开发者来说,CORS通信与同源的 ...
- js实现checkbox全选,全部选和反选效果
效果: 源码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...