Thinking in java 第21章 并发 在阻塞时终结

一个线程可以处于以下四种状态:

  1.       新建(new):当线程被创建时,它只会短暂地处于这种状态。此时它已经分配了必需的系统资源,并执行了初始化。此时刻线程已经有资格获得CPU时间了,之后调度器将把这个线程转变为可运行状态或阻塞状态。
  2. 就绪(Runnable):这种状态下,只要调度器把时间片分配给线程,线程就可以运行。也就是说,在任意时刻,线程可以运行也可以不运行。只要调度器能分配时间片给线程,它就可以运行,这不同于死亡和阻塞状态。
  3. 阻塞(Blocked):线程能够运行,但又某个条件阻止它运行。当线程处于阻塞状态时,调度器将忽略线程,不会分配给线程任何CPU时间,直到线程重新进入了就绪状态,它天才有可能执行操作
  4. 死亡(Dead):处于死亡或终止状态的线程将不在时可调度的,并且在也不会得到CPU时间,它的任务已结束,或不再时可运行的,任务死亡的通常方式时从run()方法种返回,但是任务的线程还可以被中断,你将看到这一点。

进入阻塞状态,可能有乳腺原因:

  1. sleep休眠
  2. 通过调用wait()线程挂起。直到线程得到了notify()或notifyAll()
  3. 任务在等待某个输入/输出完成。
  4. 任务试图在某个对象上表用其他同步控制方法,但是对象锁不可用,但似乎对象锁不可用,因为另外一个任务已经获取了锁

在代码种,我们应该尽量避免对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自动响应中断,关闭也能退出阻塞

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值