線程的中斷(Lock與synchronized)

  Thread包含interrupt()方法,所以你能夠終止被阻塞的任務,這個方法將設置線程的中斷狀態。若是一個線程已經被阻塞,或者試圖執行一個阻塞操做。那麼設置這個線程的中斷狀態將java

拋出InterruptedException。當拋出改異常或者該任務調用Thread.interrupted()時,中斷狀態將被複位。git

  查看Thread的API,關於中斷的方法有:併發

  void interrupt()   interrupts this threadapp

  static boolean interrupted()  Test whether the current thread has been interruptedide

  boolean isInterrupted()  Test whether the current thread has been interrupted高併發

  經過幾個例子看一下中斷的用法和特色:ui

  例子一,分別模擬了,中斷線程sleep,I/O和synchronized修飾的方法。結論:調用interrupt()方法,只有sleep的線程能夠被中斷,I/O和用synchronized修飾的線程是不能被中斷的this

public class Interrupting {
    private static ExecutorService service = Executors.newCachedThreadPool();

    static void test(Runnable r) throws InterruptedException{
        Future<?> f = service.submit(r);
        TimeUnit.MILLISECONDS.sleep(100);
        System.out.println("Interrupting: " + r.getClass().getName());
        f.cancel(true); //interrupts if running
        System.out.println("interrupted send to: " + r.getClass().getName());

    }
    public static void main(String[] args) throws Exception{
//        test(new SleepBlocked());
//        test(new IOBlocked(System.in));
        test(new SynchronizedBlocked());
        TimeUnit.SECONDS.sleep(10);
        System.out.println("Aborting with System.exit(0)");
        System.exit(0);
    }
}

class SleepBlocked implements Runnable {
    @Override
    public void run() {
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            System.out.println("InterruptedException");
        }
        System.out.println("Exiting SleepBlocked.run()");
    }
}

class IOBlocked implements Runnable {
    private InputStream is;

    public IOBlocked(InputStream is) {
        this.is = is;
    }

    @Override
    public void run() {
        try {
            System.out.print("waiting for read:");
            is.read();
        } catch (IOException e) {
            if(Thread.currentThread().isInterrupted()) {
                System.out.println("Interrupted IO Blocked");
            } else {
                throw new RuntimeException(e);
            }
        }
        System.out.println("Exiting IOBlocked.run()");
    }
}

class SynchronizedBlocked implements Runnable {
    public SynchronizedBlocked() {
        new Thread(){
            @Override
            public void run() {
                f();
            }
        }.start();
    }

    public synchronized void f() {
        while(true) { //Never release lock
            Thread.yield();
        }
    }
    @Override
    public void run() {
        System.out.println("try to call f()");
        f();
        System.out.println("Exiting SynchronizedBlocked.run()");
    }
}

   例子二,sleep是能夠被中斷的,中斷後,中斷標識位「復位」spa

package org.burning.sport.javase.thread.interrupt;

import java.util.concurrent.TimeUnit;

public class InterruptSleep implements Runnable{
    @Override
    public void run() {
        try {
            while (true) {
                System.out.println("開始睡了");
                TimeUnit.SECONDS.sleep(3);
            }
        } catch (InterruptedException e) {
            boolean isInterrupt = Thread.interrupted();
            //中斷狀態被複位
            System.out.println("中斷狀態:" + isInterrupt);
        }
    }

    public static void main(String[] args) throws Exception{
        Thread t = new Thread(new InterruptSleep());
        t.start();
        TimeUnit.SECONDS.sleep(5);
        t.interrupt();
        System.out.println("interrupted is: " + t.isInterrupted());
    }


}
/*
開始睡了
開始睡了
interrupted is: false
中斷狀態:false
 */

  例子三,普通方法是中斷不了的,而且從最後的輸出結果 interrupted is: true 看出中斷標識位沒有被清除。線程

package org.burning.sport.javase.thread.interrupt;

import java.util.concurrent.TimeUnit;

public class InterruptCommonTest implements Runnable{
    @Override
    public void run() {
        while (true) {
            System.out.println("你中斷一個試試");
            boolean interrupt = Thread.interrupted();
            System.out.println("中斷狀態" + interrupt);
        }
    }

    public static void main(String[] args) throws Exception{
        Thread t = new Thread(new InterruptCommonTest());
        t.setDaemon(true);
        t.start();
        TimeUnit.SECONDS.sleep(5);
        t.interrupt();
        System.out.println("interrupted is: " + t.isInterrupted());
    }
}
/*
中斷狀態false
你中斷一個試試
中斷狀態false
你中斷一個試試
中斷狀態false
interrupted is: true
你中斷一個試試
中斷狀態false
 */

   總結:你可以中斷對sleep的調用(或者任何要求拋出InterruptedException的調用)。可是你不能中斷正在試圖獲取synchronized鎖或者正在試圖執行IO操做的線程

   例子四:Lock與中斷的關係。

   上面的例子中看到,synchronized是不能被中斷的,可是Lock是能夠被中斷的。這個算是synchronized和Lock的不一樣點。查看Lock的API,有一個方法

   void lockInterruptibly() throws InrruptedException 就是能夠被中斷的方式來獲取鎖的方法。

package org.burning.sport.javase.thread.interrupt;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class InterruptLockTest implements Runnable{
    private static ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        try {
            lock.lockInterruptibly();
            while(true) {
                Thread.yield();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public static void main(String[] args) throws Exception{
        InterruptLockTest lockTest = new InterruptLockTest();
        Thread t1 = new Thread(lockTest);
        Thread t2 = new Thread(lockTest);
        t1.start();
        t2.start();
        TimeUnit.SECONDS.sleep(3);
        t2.interrupt();
        System.out.println("結束...");
    }
}
/*
結束...
java.lang.InterruptedException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
    at org.burning.sport.javase.thread.interrupt.InterruptLockTest.run(InterruptLockTest.java:18)
    at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
    at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
    at org.burning.sport.javase.thread.interrupt.InterruptLockTest.run(InterruptLockTest.java:25)
    at java.lang.Thread.run(Thread.java:745)
 */

 

 

  

https://gitee.com/play-happy/base-project

參考:

  【1】《Think in Java》,21.3.4 中斷

  【2】《Java 高併發程序設計》,2.2.3 線程中斷

相關文章
相關標籤/搜索