1. 程式人生 > >java併發程式設計實戰:取消與關閉筆記

java併發程式設計實戰:取消與關閉筆記

在Java中無法搶佔式地停止一個任務的執行,而是通過中斷機制實現了一種協作式的方式來取消任務的執行。

設定取消標誌

public class MyTask implements Runnable {
    private final ArrayList<BigInteger> primes = new ArrayList<BigInteger>();
    private volatile boolean cancelled;
    @Override
    public void run() {
        while (!cancelled) {
          ...
        }
    }

    public
void cancel() { cancelled = true; } }

中斷執行緒的執行

 public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }


    public boolean isInterrupted() {
        return isInterrupted(false);
    }


    private native boolean isInterrupted(boolean ClearInterrupted);

interrupt方法試圖中斷執行緒並設定中斷狀態標誌變數為true;
isInterrupted方法測試執行緒是否已經中斷,返回中斷狀態變數的值;
interrupted方法用於清除執行緒的中斷狀態,並返回之前的值,即如果當前執行緒是中斷狀態,則重新設定為false,並且返回true;

呼叫interrupt並不意味著必然停止目標執行緒工作,它緊緊傳遞了請求中斷資訊。

阻塞方法與執行緒的中斷

大部分的阻塞方法都是響應中斷的,即這些方法線上程中執行時如果發現執行緒被中斷,會清除執行緒的中斷狀態,並丟擲InterruptedException表示該方法的執行過程被從外部中斷。響應中斷的阻塞方法通常會在入口處先檢查執行緒的中斷狀態,執行緒不是中斷狀態時,才會繼續執行。

class PrimeProducer extends Thread{
        private final BlockingQueue<BigInteger> queue;
        private volatile boolean cancelled;

        PrimeProducer(BlockingQueue<BigInteger> queue){
            this.queue = queue;
        }

        public void run(){
            BigInteger p = BigInteger.ONE;
            while(!Thread.currentThread().isInterrupted(){
                queue.put(p = p.nextProbablePrime());
                }catch(InterruptedException consumed){
                    /*允許執行緒退出*/
                }
            }

        public void cancel(){
            interrupt();
        }
}

中斷響應

當呼叫可中斷的阻塞方法時,有兩種策略可用於處理InterruptedException
1、傳遞異常,從而使你的方法也成為可中斷的阻塞方法。
2、恢復中斷狀態,從而使呼叫棧上中的上層程式碼能夠對其進行處理。
只有實現了執行緒中斷策略的程式碼才可以遮蔽中斷請求,常規任務中不應該遮蔽中斷請求。

通過Future實現取消

public class TimedRun {
    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 {
            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
        }
    }
}

Future介面有一個cancel方法,可以通過該方法取消任務的執行,cancel方法有一個boolean型的引數mayInterruptIfRunning。

如果設定為false,對於正在執行的任務只能等到任務執行完畢,無法中斷;

如果設定為true,對於正在執行的任務可以試圖中斷任務的執行,這種情況通常只在與Executor框架配合時使用,因為執行任務的執行緒是由Executor建立的,Executor知道該如何中斷執行任務的執行緒;