线程的四种状态
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.BufferedInputStreamIOBlock 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