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并发编程系列很不错,值得收藏. 为了方便各位网友学习以及方便自己复习之用 ...
随机推荐
- SQL函数(不定时更新)
sum求和:select sum(a) from table1 group by b 依据b列为a列求和 distinct去除重复:select distinct(a) from table1 ...
- 动态生成select框内容
获取动态数据,显示在select选项中,当前select在jsp页面中 <select > <option>这里放选中或者当前的数据</option> <%f ...
- NetEaseGame/ATX 的MD
# ATX(AutomatorX) (中文版)[](ht ...
- bzoj1801中国象棋
题目链接 很裸的$dp+$组合计数 注意 注意 注意 $BZOJ$不要用玄学优化 $CE$不管$qwq$ /********************************************** ...
- spring的包大概作用(备忘)
1.spring.jar 是包含有完整发布模块的单个jar 包. 2. org.springframework.aop 包含在应用中使用Spring的AOP特性时所需的类. 3. org.spring ...
- [译文]casperjs 的API-casper模块
Casper class: 可以通过这个模块的create()方法来获取这个模块的一个实例,这是最容易的: var casper = require('casper').create(); 我们也可以 ...
- 编译图像质量分析库iqa
介绍 iqa库是我在GitHub上偶然发现的一个具有MSE, PSNR, SSIM, MS-SSIM等图像质量分析算法的库,觉得还不错,就把它下载下来编译,编译后生成静态的库.以下是我总结的编译方 ...
- 动手玩转Docker(二)
CentOS7下安装docker: 通过命令uname -r 查看linux内核版本,版本低的话不支持docker. [tim@num root]$ uname -r 3.10.0-514.el7.x ...
- Mysql:如果数据存在则更新,不存在则插入
mysql语法支持如果数据存在则更新,不存在则插入,首先判断数据存在还是不存在的那个字段要设置成unique索引, 例如表tb_addrbook如下: 索引: 语句1:不存在插入 INSERT INT ...
- python全栈开发_day3_数据类型,输入输出及运算符
一:常见数据类型 1)int整型 例:age=1 整型常用于年龄,账号等 2)float浮点型 例:salary=5.1 浮点型常用于薪水,身高,体重等 3)str字符串类型 例:name=“chen ...