java自定义终止程序_java并发编程(1)并发程序的取消于关闭

一、任务的取消于关闭

1、中断Thread

1.每个线程都有一个boolean类型的中断状态。true则是中断状态中

interrupt:发出中断请求;isInterrupt:返回中断状态;interrupted:清除中断状态

2.JVM中的阻塞方法会检查线程中断状态,其响应方法为:清除中断状态,抛出InterruptedException异常,表示阻塞操作被中断结束 ;但JVM不保证阻塞方法何时检测到线程的中断状态

3.中断的理解:不会真正的中断一个正在运行的线程,而只是发出请求,具体的中断由任务自己处理

通过中断来取消线程通常是最好的方法

public class PrimeProducer extendsThread {private final BlockingQueuequeue;

PrimeProducer(BlockingQueuequeue) {this.queue =queue;

}public voidrun() {try{

BigInteger p=BigInteger.ONE;while (!Thread.currentThread().isInterrupted())

queue.put(p=p.nextProbablePrime());

}catch(InterruptedException consumed) {/*Allow thread to exit*/

//如果捕获到中断异常,则由线程自己退出

}

}public voidcancel() {

interrupt();

}

}

2、不可中断的阻塞的中断

如:Socket I/O操作,即使设置了中断请求,也不会中断,但是close 套接字,会使其抛出异常,达到中断效果;因此我们要重写中断方法

//自定义callable实现类

public abstract class SocketUsingTask implements CancellableTask{privateSocket socket;protected synchronized voidsetSocket(Socket s) {

socket=s;

}//取消方法

public synchronized voidcancel() {try{if (socket != null)

socket.close();

}catch(IOException ignored) {

}

}//新建实例的方法

public RunnableFuturenewTask() {return new FutureTask(this) {public boolean cancel(booleanmayInterruptIfRunning) {try{

SocketUsingTask.this.cancel();

}finally{return super.cancel(mayInterruptIfRunning);

}

}

};

}

}//自定义callable接口

interface CancellableTask extends Callable{voidcancel();

RunnableFuturenewTask();

}//自定义 执行池

class CancellingExecutor extendsThreadPoolExecutor {

......//通过改写newTaskFor 返回自己的Callable

protected RunnableFuture newTaskFor(Callablecallable) {if (callable instanceofCancellableTask)return ((CancellableTask) callable).newTask();else

return super.newTaskFor(callable);

}

}

3、通过自定义取消计时任务

private static final ScheduledExecutorService cancelExec = newScheduledThreadPool(1);/***

*@paramr 任务

*@paramtimeout 超时时间

*@paramunit TimeUnit

*@throwsInterruptedException*/

public static void timedRun(final Runnable r,long timeout, TimeUnit unit) throwsInterruptedException {class RethrowableTask implementsRunnable {//通过一个volatile变量,来存储线程是否异常

private volatileThrowable t;public voidrun() {try{

r.run();

}catch(Throwable t) {this.t =t;

}

}private voidrethrow() {if (t != null)throwlaunderThrowable(t);

}

}

RethrowableTask task= newRethrowableTask();final Thread taskThread = newThread(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) throwsInterruptedException {

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

throwlaunderThrowable(e.getCause());

}finally{//Harmless if task already completed

task.cancel(true); //interrupt if running

}

}

二、停止基于线程的服务

1.通常,服务不能直接中断,造成服务数据丢失

2.线程池服务也不能直接中断

1、日志服务

标准的生产者,消费者模式

public classLogService {private final BlockingQueuequeue;private finalLoggerThread loggerThread;private finalPrintWriter writer;private booleanisShutdown;private intreservations;publicLogService(Writer writer) {this.queue = new LinkedBlockingQueue();this.loggerThread = newLoggerThread();this.writer = newPrintWriter(writer);

}public voidstart() {

loggerThread.start();

}public voidstop() {synchronized (this) {

isShutdown= true;

}

loggerThread.interrupt();//发出中断

}public void log(String msg) throwsInterruptedException {synchronized (this) {if(isShutdown){throw new IllegalStateException(/*...*/);

}++reservations; //保存的正确的在队列中的日志数量

}

queue.put(msg);//将日志放入队列

}private class LoggerThread extendsThread {public voidrun() {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 extendsAbstractExecutorService {private finalExecutorService exec;private final Set tasksCancelledAtShutdown =Collections.synchronizedSet(new HashSet());publicTrackingExecutor() {

exec=Executors.newSingleThreadExecutor();

}/*public TrackingExecutor(ExecutorService exec) {

this.exec = exec;

}*/

public voidshutdown() {

exec.shutdown();

}public ListshutdownNow() {returnexec.shutdownNow();

}public booleanisShutdown() {returnexec.isShutdown();

}public booleanisTerminated() {returnexec.isTerminated();

}public boolean awaitTermination(longtimeout, TimeUnit unit)throwsInterruptedException {returnexec.awaitTermination(timeout, unit);

}public ListgetCancelledTasks() {if (!exec.isTerminated())throw new IllegalStateException(/*...*/);return new ArrayList(tasksCancelledAtShutdown);

}public void execute(finalRunnable runnable) {

exec.execute(newRunnable() {public voidrun() {try{

runnable.run();

}finally{if(isShutdown()&&Thread.currentThread().isInterrupted())

tasksCancelledAtShutdown.add(runnable);

}

}

});

}

@Testpublic void test() throwsInterruptedException {

ExecutorService executorService=Executors.newSingleThreadExecutor();

TrackingExecutor trackingExecutor= newTrackingExecutor();

trackingExecutor.execute(newRunnable() {

@Overridepublic voidrun() {try{

Thread.sleep(2000);

System.err.println("123123");

}catch(InterruptedException e) {

Thread.currentThread().interrupt();//设置状态 或继续抛,在execute中处理

e.printStackTrace();

}finally{

}

}

});

List runnables =trackingExecutor.shutdownNow();

trackingExecutor.awaitTermination(10,TimeUnit.SECONDS);

List 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退出、守护线程等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值