Java并发编程实战 之 线程的取消与关闭

任务取消

场景

  • 用户手动取消。
  • 线程超时。
  • 线程提前结束,已经得到结果。
  • 发生错误。
  • 主线程关闭。
  • java没有抢占式的线程停止方式,必须依靠线程本身与外部状态通过协作式的方式停止。

线程中断

  • 通过设置状态位,并在某些方法中去检查这个状态位,但是这些可以响应中断状态的方法,可能被阻塞,例如调用BlockingQueue的put方法。

中断方法

  • 每个线程都由一个静态的中断状态位,interrupt
  • interrupt() 中断线程,但是不清除状态位。
  • interrupted() 清除当前中断状态,并返回之前的值。

一般说来,当可能阻塞的方法声明中有抛出InterruptedException则暗示该方法是可中断的,如BlockingQueue#put、BlockingQueue#take、Object#wait、Thread#sleep等

中断策略

  • 抛出InterruptedException,来通知上一层的代码。
  • 恢复中断状态使上一层代码可以检查到。

通过Future来实现取消

  Future<?>task=taskExec.submit(r);
   try{
       task.get(timeout,unit);
   }
   catch (TimeoutExceptione){
     //下面任务会被取消
   }
   catch (ExecutionExceptione){
     //task中抛出的异常;重抛出
     throw launderThrowable(e.getCause());
   }
   finally{
     //如果任务已经结束,是无害的
     task.cancerl(true);
   }
}

处理不可中断的阻塞

  • 不响应中断的方法
    • Socket I/O ,read和write方法,可以通过强行关闭Socket中断。
    • 同步I/O
    • Selector的异步I/O,如果调用select方法的时候阻塞了,可以通过调用close方法或wakeup方法,使
      其抛出ClosedSelectorException
    • 获取一个锁的时候,也不会响应中断,但是Lock的lockInterruptibly,弥补了这些不足,它允许等待锁的同时,可以响应中断。
  • 通过重写Thread的interrupt方法来解决上述的不响应中断的类的中断问题。
package net.jcip.examples;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

/**
 * ReaderThread
 * <p/>
 * Encapsulating nonstandard cancellation in a Thread by overriding interrupt
 *
 * @author Brian Goetz and Tim Peierls
 */
public class ReaderThread extends Thread {
    private static final int BUFSZ = 512;
    private final Socket socket;
    private final InputStream in;

    public ReaderThread(Socket socket) throws IOException {
        this.socket = socket;
        this.in = socket.getInputStream();
    }

    public void interrupt() {
        try {
            socket.close();
        } catch (IOException ignored) {
        } finally {
            super.interrupt();
        }
    }

    public void run() {
        try {
            byte[] buf = new byte[BUFSZ];
            while (true) {
                int count = in.read(buf);
                if (count < 0)
                    break;
                else if (count > 0)
                    processBuffer(buf, count);
            }
        } catch (IOException e) { /* Allow thread to exit */
        }
    }

    public void processBuffer(byte[] buf, int count) {
    }
}

通过newTaskFor来封装非标准的取消

  • 讲的是 如何扩展Future的cancel方法。
package net.jcip.examples;

import java.io.IOException;
import java.net.Socket;
import java.util.concurrent.*;

import net.jcip.annotations.*;

/**
 * SocketUsingTask
 * <p/>
 * Encapsulating nonstandard cancellation in a task with newTaskFor
 *
 * @author Brian Goetz and Tim Peierls
 */

public abstract class SocketUsingTask <T> implements CancellableTask<T> {
    @GuardedBy("this") 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);
                }
            }
        };
    }
}


interface CancellableTask <T> extends Callable<T> {
    void cancel();

    RunnableFuture<T> newTask();
}


@ThreadSafe
class CancellingExecutor extends ThreadPoolExecutor {
    public CancellingExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public CancellingExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    public CancellingExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public CancellingExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        if (callable instanceof CancellableTask)
            return ((CancellableTask<T>) callable).newTask();
        else
            return super.newTaskFor(callable);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值