Future机制用于并发编程时的死锁检测

Netty源码里面有个类:DeadLockProofWorker,源码如下:

 public static final ThreadLocal<Executor> PARENT = new ThreadLocal<Executor>();

    public static void start(final Executor parent, final Runnable runnable) {
        if (parent == null) {
            throw new NullPointerException("parent");
        }
        if (runnable == null) {
            throw new NullPointerException("runnable");
        }

        parent.execute(new Runnable() {
            public void run() {
                PARENT.set(parent);
                try {
                    runnable.run();
                } finally {
                    PARENT.remove();
                }
            }
        });
    }

    private DeadLockProofWorker() {
        super();
    }

假设有下面的代码:

 ChannelFuture f = AChannelHandlerContext.getChannel().write(res);  
     f.addListener(new ChannelFutureListener() {              
@Override  
public void operationComplete(ChannelFuture future) throws Exception {  
    future.await();//(1)Thread 1 waiting for itself to be done.    
 //ChannelFuture f is done only if this invoke returns.  
});  
    f.await();//(2)Thead 2 wait for f to be done. 
 

如果ChannelFuture没有死锁检测,那么这两个线程将永远处于死锁状态。

Thread2 等待ChannelFuture f 完成,ChannelFuture f 必须把listener的代码跑完才会完成,而listener也在等待future完成,于是死锁就造成了。

看如何用线程变量杜绝死锁。

上述代码: AChannelHandlerContext.getChannel().write(res) 会把写的操作放到线程池里异步进行,并且是这样放进去的:

DeadLockProofWorker.start(executor, ARunnable r).

上面的代码在r运行的线程里面可以通过DeadLockProofWorker.PARENT.get()获取到executor,即一个非null的对象,如果在f.await()里面检测一下,就可以知道await是否在r的线程里面了:

 public ChannelFuture await() throws InterruptedException {
        ...
        checkDeadLock();
        ...      
        return this;
}

 private static void checkDeadLock() {
        if (DeadLockProofWorker.PARENT.get() != null) {
            throw new IllegalStateException(
                    "await*() in I/O thread causes a dead lock or " +
                    "sudden performance drop. Use addListener() instead or " +
                    "call await*() from a different thread.");
        }
    }

如果DeadLockProofWorker.PARENT.get() != null 成立,那么当前线程就是启动线程1,然后抛出异常避免死锁。

原文地址:https://www.cnblogs.com/cwjcsu/p/8433073.html