什么案例需要Java中的同步方法访问?

use*_*732 19 java methods concurrency synchronization non-static

在什么情况下需要同步访问实例成员?我理解,对类的静态成员的访问总是需要同步 - 因为它们在类的所有对象实例之间共享.

我的问题是,如果我不同步实例成员,我什么时候会不正确?

例如,如果我的班级是

public class MyClass {
    private int instanceVar = 0;

    public setInstanceVar()
    {
        instanceVar++;
    }

    public getInstanceVar()
    {
        return instanceVar;
    }
}
Run Code Online (Sandbox Code Playgroud)

在什么情况下(使用类MyClass)我需要有方法: public synchronized setInstanceVar()public synchronized getInstanceVar()

提前感谢您的回答.

Dan*_*wak 37

synchronized修饰符实在是一个糟糕的主意,应该不惜一切代价避免.我认为值得称道的是,Sun试图让锁定更容易实现,但synchronized只会造成比它值得更多的麻烦.

问题是,synchronized方法实际上只是用于获取锁定this并在方法持续时间内持有它的语法糖.因此,public synchronized void setInstanceVar()相当于这样的事情:

public void setInstanceVar() {
    synchronized(this) {
        instanceVar++;
    }
}
Run Code Online (Sandbox Code Playgroud)

这有两个原因:

  • synchronized同一类中的所有方法都使用完全相同的锁,这会降低吞吐量
  • 任何人都可以访问锁,包括其他类的成员.

没有什么可以阻止我在另一个类中做这样的事情:

MyClass c = new MyClass();
synchronized(c) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

在该synchronized块中,我持有所有synchronized方法所需的锁MyClass.这进一步降低了吞吐量并大大增加了死锁的可能性.

更好的方法是拥有一个专用lock对象并synchronized(...)直接使用该块:

public class MyClass {
    private int instanceVar;
    private final Object lock = new Object();     // must be final!

    public void setInstanceVar() {
        synchronized(lock) {
            instanceVar++;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用java.util.concurrent.Lock接口和java.util.concurrent.locks.ReentrantLock实现来实现基本相同的结果(事实上,它在Java 6上是相同的).

  • "lock"不需要"静态",因为它正在同步的数据(`instanceVar`)本身不是静态的.静态锁几乎总是一个非常非常严重的问题的迹象,你应该尽可能避免它们. (3认同)

Jon*_*eet 20

这取决于您是否希望您的类是线程安全的.大多数类不应该是线程安全的(为简单起见),在这种情况下,您不需要同步.如果您需要它是线程安全的,您应该同步访问使变量volatile.(它避免了其他线程获得"陈旧"数据.)