一个线程可以处于以下四种状态:
- 新建(new):当线程被创建时,它只会短暂地处于这种状态。此时它已经分配了必需的系统资源,并执行了初始化。此时刻线程已经有资格获得CPU时间了,之后调度器将把这个线程转变为可运行状态或阻塞状态。
- 就绪(Runnable):这种状态下,只要调度器把时间片分配给线程,线程就可以运行。也就是说,在任意时刻,线程可以运行也可以不运行。只要调度器能分配时间片给线程,它就可以运行,这不同于死亡和阻塞状态。
- 阻塞(Blocked):线程能够运行,但又某个条件阻止它运行。当线程处于阻塞状态时,调度器将忽略线程,不会分配给线程任何CPU时间,直到线程重新进入了就绪状态,它天才有可能执行操作
- 死亡(Dead):处于死亡或终止状态的线程将不在时可调度的,并且在也不会得到CPU时间,它的任务已结束,或不再时可运行的,任务死亡的通常方式时从run()方法种返回,但是任务的线程还可以被中断,你将看到这一点。
进入阻塞状态,可能有乳腺原因:
- sleep休眠
- 通过调用wait()线程挂起。直到线程得到了notify()或notifyAll()
- 任务在等待某个输入/输出完成。
- 任务试图在某个对象上表用其他同步控制方法,但是对象锁不可用,但似乎对象锁不可用,因为另外一个任务已经获取了锁
在代码种,我们应该尽量避免对Thread对象直接操作,使用Executors来进行操作:
class SleepBlocked implements Runnable {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {
System.out.println("InterruptedException");
}
System.out.println("Exiting SleepBlocked.run()");
}
}
class IOBlocked implements Runnable {
private final InputStream in;
public IOBlocked(InputStream is){
in = is;
}
public void run(){
try {
System.out.println("Waiting for read():");
in.read();
} catch (IOException e) {
if(Thread.currentThread().isInterrupted()){
System.out.println("Interrupted from blocked I/O");
}else{
throw new RuntimeException(e);
}
}
System.out.println("Exiting IOBlocked.run()");
}
}
class SynchronizedBlocked implements Runnable {
public synchronized void f(){
while(true)
Thread.yield();
}
public SynchronizedBlocked(){
new Thread(){
public void run(){
f();
}
}.start();
}
@Override
public void run() {
System.out.println("Try to call f()");
f();
System.out.println("Exiting SynchronizedBlocked.run()");
}
}
public class Interrupting {
private static ExecutorService exec = Executors.newCachedThreadPool();
static void test(Runnable r) throws InterruptedException{
Future<?> f = exec.submit(r);
TimeUnit.MICROSECONDS.sleep(100);
System.out.println("Interruption " + r.getClass().getName());
f.cancel(true);
System.out.println("Interrupt sent 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(3);
System.out.println("Aborting with System.exit(0)");
System.exit(0);
}
}
运行上面的程序,可以知道,你能够中断sleep成都的阻塞,但时你不能中断正在获取锁,或者创建执行IO任务时,有一个稍显笨拙的有效方法:
public class ClseResource {
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
ServerSocket server = new ServerSocket(8080);
InputStream socketInput = new Socket("localhost",8080).getInputStream();
exec.execute(new IOBlocked(socketInput));
exec.execute(new IOBlocked(System.in));
TimeUnit.MICROSECONDS.sleep(100);
System.out.println("Shuttion 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():
Shuttion down all threads
Closing java.net.SocketInputStream
Interrupted from blocked I/O
Exiting IOBlocked.run()
Closing java.io.BufferedInputStream
关闭底层任务将接触阻塞,
还有一种更加人性化的方案:
class NIOBlocked implements Runnable {
private final SocketChannel sc;
public NIOBlocked(SocketChannel sc){
this.sc = sc;
}
@Override
public void run() {
try {
System.out.println("Waiting for read() in " + this);
sc.read(ByteBuffer.allocate(1));
}catch(ClosedByInterruptException e){
System.out.println("ClosedByInterruptException");
}catch(AsynchronousCloseException e1){
System.out.println("AsynchronousCloseException");
}catch (IOException e) {
throw new RuntimeException();
}
System.out.println("Exiting NIOBlocked.run()" + this);
}
}
public class NIOInterruption {
public static void main(String[]args) throws Exception{
ExecutorService exec = Executors.newCachedThreadPool();
ServerSocket server = 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);
TimeUnit.SECONDS.sleep(1);
sc2.close();
}
}
Waiting for read() in com.yaoqiang.demo.Thread.NIOBlocked@1bc5ece8
Waiting for read() in com.yaoqiang.demo.Thread.NIOBlocked@4768105a
ClosedByInterruptException
Exiting NIOBlocked.run()com.yaoqiang.demo.Thread.NIOBlocked@1bc5ece8
AsynchronousCloseException
Exiting NIOBlocked.run()com.yaoqiang.demo.Thread.NIOBlocked@4768105a
在这种情况下,NIO自动响应中断,关闭也能退出阻塞