一、任务的取消于关闭

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)并发程序的取消于关闭的更多相关文章

  1. <<java 并发编程>>第七章:取消和关闭

    Java没有提供任何机制来安全地终止线程,虽然Thread.stop和suspend等方法提供了这样的机制,但是存在严重的缺陷,应该避免使用这些方法.但是Java提供了中断Interruption机制 ...

  2. Java并发编程:并发容器之ConcurrentHashMap(转载)

    Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...

  3. Java并发编程:并发容器之ConcurrentHashMap

    转载: Java并发编程:并发容器之ConcurrentHashMap JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的 ...

  4. Java并发编程:并发容器ConcurrentHashMap

    Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...

  5. 【转】Java并发编程:并发容器之ConcurrentHashMap

    JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都串行化了,这样保证了线程的安全性,所以这种方法的代价就是严重降低了 ...

  6. Java并发编程:并发容器之ConcurrentHashMap(转)

    本文转自:http://www.cnblogs.com/dolphin0520/p/3932905.html Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载 ...

  7. 10、Java并发编程:并发容器之ConcurrentHashMap

    Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...

  8. Java并发编程:并发容器之CopyOnWriteArrayList(转载)

    Java并发编程:并发容器之CopyOnWriteArrayList(转载) 原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW ...

  9. Java并发编程:并发容器之CopyOnWriteArrayList

    转载: Java并发编程:并发容器之CopyOnWriteArrayList Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个 ...

  10. 【Java并发编程】并发编程大合集-值得收藏

    http://blog.csdn.net/ns_code/article/details/17539599这个博主的关于java并发编程系列很不错,值得收藏. 为了方便各位网友学习以及方便自己复习之用 ...

随机推荐

  1. [Erlang00]:gen_server:reply/2

    --- gen_server:reply/2 reply(Client, Reply) –> Result      Types:     Client - see below     Repl ...

  2. Javascript:日期排班功能实现

     背景: 近期,公司的产品经常会遇到日期排班类似的功能: 需求的排班日期长短不一:有些是两周,有些是四周:要求选中的时候有一个active的状态区分,另外要提供钩子获取选中日期的形如:[2018-04 ...

  3. 逃生(反向topo)

    逃生 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status De ...

  4. 【bzoj4889】: [Tjoi2017]不勤劳的图书管理员 分块-BIT

    [bzoj4889]: [Tjoi2017]不勤劳的图书管理员 题目大意:给定一个序列(n<=50000),每个数有一个编码ai(ai<=50000)和权值vi(vi<=100000 ...

  5. 洛谷P4220 [WC2018]通道(边分治+虚树)

    题面 传送门 题解 代码不就百来行么也不算很长丫 虽然这题随机化贪心就可以过而且速度和正解差不多不过我们还是要好好学正解 前置芝士 边分治 米娜应该都知道点分治是个什么东西,而边分治,顾名思义就是对边 ...

  6. linux下的常用指令

    1,在vim中查找字符段 :1?字段名,此方式可以从开始向下查询字段了. :?字段名 ,查询字都段: 2,修改某个文件夹用户和组 修改文件所属用户:chown [-R] 用户 文件或目录 如:chow ...

  7. unicode 转换成中文

    unicode 转换成中文 + (NSString *)replaceUnicode:(NSString *)unicodeStr { NSString *tempStr1 = [unicodeStr ...

  8. Linux rsync 企业级应用

    简介 rsync 是 Linux 下的数据同步工具, 其支持本地同步和远程同步, 远程同步分为 daemon 和 ssh 同步方式    rsync 可以代替 cp, scp 等命令, 且具有更高的可 ...

  9. react-router的简单使用

    React Router是一个基于React之上的强大路由库,可以让你向应用中快速的添加视图和数据流,同时保持页面与URL间的同步. 1.安装: npm install --save react-ro ...

  10. rest-framework框架组件

    序列化组件 创建一个序列化类, 视图四种方式 以下代码都需要创建一个serializers.py文件 from rest_framework import serializers from CBV_a ...