为什么Goetz不再使用volatile boolean for Listing 7.20?

时间:2018-01-08 01:11:48

标签: java multithreading concurrency final atomicboolean

以下是Brian Goetz的 Java Concurrency in Practice 中列出7.20的代码:

public class CheckForMail {
    public boolean checkMail(Set<String> hosts, long timeout, TimeUnit unit)
            throws InterruptedException { 
        ExecutorService exec = Executors.newCachedThreadPool();
        final AtomicBoolean hasNewMail = new AtomicBoolean(false);

        try { 
            for (final String host : hosts)     
                exec.execute(new Runnable() { 
                    public void run() { 
                        if (checkMail(host)) hasNewMail.set(true);
                    }
                }); 
        } finally { 
            exec.shutdown();
            exec.awaitTermination(timeout, unit); 
        } 
        return hasNewMail.get();
    } 

    private boolean checkMail(String host) { // Check for mail return
        false;
    }
}

参考此代码,Goetz说“使用AtomicBoolean而不是volatile布尔值的原因是为了从内部Runnable访问hasMail标志,它必须是final,这将排除修改它”( p.158)。

为什么 才能成为最终版?难道你不能让它成为一个非最终的布尔波动?

2 个答案:

答案 0 :(得分:6)

  

但为什么 最终?难道你不能让它成为一个非最终的布尔波动?

正如Goetz所说,需要从内部hasNewMail访问

Runnable。这是内部类的一个实例。在最新版本的Java中,变量“有效最终”是内部类访问词法封闭方法的局部变量的要求。我认为Goetz在需求更强的时候写作:变量确实是final。 “有效最终”和final之间的区别对于此目的并不重要,但无论如何,变量都无法修改。

请注意,Goetz代码中的AtomicBooleanfinal。它本身不能修改,但存储在中的值可以是,这就是程序的工作方式。

答案 1 :(得分:2)

局部变量不可能是易变的。如果您尝试进行更改,则会发现它是编译错误。

顺便提一下,从Java 8开始,您不再需要将变量标记为final;只要它是effectively final(也就是说,你没有在第一次之后设置它),Java就会接受它,就像你将它标记为最终一样。