同步对易失性字段的写访问(廉价读写块)

obe*_*ger 8 java multithreading synchronization volatile thread-safety

假设我有以下类会被大量读取,但只是偶尔写入.它将用于多线程Web应用程序,因此它需要是线程安全的:

public class Foo {
    private volatile String foo;
    public String getFoo() {
        return foo;
    }
    public synchronized String setFoo(String in) {
        this.foo = in;
    }
}
Run Code Online (Sandbox Code Playgroud)

Java Concurrency(http://www.ibm.com/developerworks/java/library/j-jtp06197/index.html)指出,这是一种在提高读访问权限的同时保护写访问的脆弱方法.什么是这种模式的更强的替代品?或者,如果foo在读取繁重的环境中需要变量,还是其他任何选择?谢谢.

Evg*_*eev 15

Volatile提供对字段的快速线程安全无锁访问,无需同步

private volatile String foo;

public String getFoo() {
    return foo;
}
public void setFoo(String in) {
    this.foo = in;
}
Run Code Online (Sandbox Code Playgroud)

volatile解决了3个问题1)内存可见性2)双字段和长字段的原子写入3)禁止指令重新排序.但是,如果你需要在一个字段上进行多次操作作为一个原子事务,例如增量,那就不够了.这段代码坏了

private volatile int id;

public void incrementId() {
     id++;
}
Run Code Online (Sandbox Code Playgroud)

因为如果2个线程同时读取并递增它并保存结果,那么第一个增量的结果将被第二个增量的结果覆盖.为了防止这种情况发生,我们需要使用同步

 private int id;

 public synchronized int nextId() {
       return ++id;
 }
Run Code Online (Sandbox Code Playgroud)

或java.util.concurrent.atomic包

 private AtomicInteger id = new AtomicInteger();

 public void incrementId() {
     return id.incrementAndGet();
 }
Run Code Online (Sandbox Code Playgroud)

  • 我相信没有这种情况.如果同步对字段的访问,则volatile是多余的. (2认同)