線程的四種狀態
1. 建立(new) : 在一個線程建立時會短暫的處於這種狀態,之後調度器可以將其轉為就緒或阻塞
2. 就緒(runnable) : 這種狀態下,線程在任意時間可以運行,也可以不運行
3. 阻塞(blocked) : 這種狀態下,線程被阻止運行。只有當其重新進入就緒狀態才能繼續運行
4. 死亡(dead) : 線程不再可調度
進入阻塞狀態的原因
1. sleep() 方法的調用
2. Object類的wait()方法的調用,直到收到notify()或notifyAll()的訊息
3. 線程任務在等待輸入
4. 在調用同步方法而對象鎖不可用時
下面是一個阻塞線程的中斷例子
package threadtest2;import java.util.concurrent.TimeUnit;public class SleepBlocked extends Thread { /** * 進入一秒的睡眠阻塞 */ @Override public void run() { try { TimeUnit.MILLISECONDS.sleep(1000); } catch (InterruptedException e) { System.out.println("Sleep blocked has been interrupted"); } }}package threadtest2;import java.io.IOException;import java.io.InputStream;public class IOBlocked extends Thread { InputStream in; public IOBlocked(InputStream is) { this.in = is; } /** * 等待輸入進入IO阻塞 */ @Override public void run() { System.out.println("Waiting for read"); try { in.read(); } catch (IOException e) { if (Thread.currentThread().isInterrupted()) { System.out.println("IOBlock is interrupted"); } else { throw new RuntimeException(e); } } System.out.println("Exiting IOBlocked.run()"); }}package threadtest2;public class SyncBlocked extends Thread { /** * 線程構造方法內即調用f() */ public SyncBlocked() { (new Thread() { @Override public void run() { f(); } }).start(); } /** * 永不釋放的鎖方法 */ public synchronized void f() { while (true); } /** * 調用f()時進入阻塞 */ @Override public void run() { System.out.println("Trying to call f()"); f(); System.out.println("Exiting SyncBlocked.run()"); }}package threadtest2;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;import java.util.concurrent.TimeUnit;public class Interrupting { private static ExecutorService exec = Executors.newCachedThreadPool(); private static void test(Runnable r) throws InterruptedException { Future<?> f = exec.submit(r); TimeUnit.MILLISECONDS.sleep(100); System.out.println("Interrupting " + r.getClass().getName()); f.cancel(true); // 通過Future的cancel()方法中斷線程運行,和interrupt()效果一致 System.out.println("Interrupt signal sent to " + r.getClass().getName()); } /** * 最後的輸出證明sleep阻塞可以被中斷 * 而IO和Sync的阻塞不可被中斷 * @param args * @throws Exception */ public static void main(String[] args) throws Exception { test(new SleepBlocked()); test(new IOBlocked(System.in)); test(new SyncBlocked()); TimeUnit.SECONDS.sleep(3); System.out.println("Aborting with System.exit(0)"); System.exit(0); }}
1) 通過關閉使用資源來中止阻塞
package threadtest2;import java.io.InputStream;import java.net.ServerSocket;import java.net.Socket;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;public class CloseResource { public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); ServerSocket ss = new ServerSocket(8080); InputStream socketInput = new Socket("localhost", 8080).getInputStream(); exec.execute(new IOBlocked(socketInput)); exec.execute(new IOBlocked(System.in)); TimeUnit.MILLISECONDS.sleep(100); System.out.println("Shutting down all threads"); exec.shutdownNow(); // 至此所有線程是不能關閉的 TimeUnit.SECONDS.sleep(1); System.out.println("Closing " + socketInput.getClass().getName()); socketInput.close(); // 只有當正在使用的資源關閉後才能關閉線程 TimeUnit.SECONDS.sleep(1); System.out.println("Closing " + System.in.getClass().getName()); System.in.close(); }}
Waiting for read
Waiting for read
Shutting down all threads
Closing java.net.SocketInputStream
IOBlock is interrupted
Exiting IOBlocked.run()
Closing java.io.BufferedInputStream
IOBlock is interrupted
Exiting IOBlocked.run()
2) 通過使用NIO來響應阻塞的IO線程的插斷要求
package threadtest2;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.AsynchronousCloseException;import java.nio.channels.ClosedByInterruptException;import java.nio.channels.SocketChannel;public class NIOBlocked extends Thread { private final SocketChannel sc; public NIOBlocked(SocketChannel sc) { this.sc = sc; } @Override public void run() { System.out.println("Waiting for read in " + this); try { sc.read(ByteBuffer.allocate(1)); } catch (ClosedByInterruptException e) { // 一個通過interrupt()或者cancel()來中斷阻塞的異常 System.out.println("ClosedByInterruptException accured"); } catch (AsynchronousCloseException e) { // 一個通過關閉正在使用的資源中斷阻塞的異常 System.out.println("AsynchronousCloseException accured"); } catch (IOException e) { throw new RuntimeException(e); } System.out.println("Exiting NIOBlocked.run() " + this); }}package threadtest2;import java.io.IOException;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.nio.channels.SocketChannel;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;import java.util.concurrent.TimeUnit;public class NIOInterrupting { public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); ServerSocket ss = new ServerSocket(8080); InetSocketAddress isa = new InetSocketAddress("localhost", 8080); SocketChannel sc1 = SocketChannel.open(isa); SocketChannel sc2 = SocketChannel.open(isa); Future<?> f = exec.submit(new NIOBlocked(sc1)); exec.execute(new NIOBlocked(sc2)); exec.shutdown(); TimeUnit.SECONDS.sleep(1); f.cancel(true); // 使用NIO可以直接cancel掉阻塞的thread TimeUnit.SECONDS.sleep(1); sc2.close(); // 也可以通過close正在使用的資源來 }}
Waiting for read in Thread[Thread-0,5,main]
Waiting for read in Thread[Thread-1,5,main]
ClosedByInterruptException accured
Exiting NIOBlocked.run() Thread[Thread-0,5,main]
AsynchronousCloseException accured
Exiting NIOBlocked.run() Thread[Thread-1,5,main]
一個可以被中斷的鎖
package threadtest2;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.ReentrantLock;public class LockBlocked extends Thread { ReentrantLock lock = new ReentrantLock(); public LockBlocked() { lock.lock(); } @Override public void run() { System.out.println("Waiting for lock"); try { // 這是一個可以被interrupt打斷的鎖 lock.lockInterruptibly(); } catch (InterruptedException e) { System.out.println("Interrupted from LockBlocked.run()"); } System.out.println("Broken out of constructor lock"); } public static void main(String[] args) throws InterruptedException { Thread t = new LockBlocked(); t.start(); TimeUnit.SECONDS.sleep(2); t.interrupt(); }}
Waiting for lock
Interrupted from LockBlocked.run()
Broken out of constructor lock