什么情况下需要在Java中同步方法访问?

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

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

例如,如果我的课是

public class MyClass {
    private int instanceVar = 0;

    public setInstanceVar()
    {
        instanceVar++;
    }

    public getInstanceVar()
    {
        return instanceVar;
    }
}

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

预先感谢您的答案。


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


synchronized修饰符是一个坏主意,应该不惜一切代价避免。 我认为,Sun试图让锁定变得更容易达到令人赞叹,但synchronized只会导致更多的麻烦而不值得。

问题是,一个synchronized方法实际上是获取上的锁只是语法糖this并保持该方法的持续时间。 因此, public synchronized void setInstanceVar()将相当于这样的事情:

public void setInstanceVar() {
    synchronized(this) {
        instanceVar++;
    }
}

这有两个原因是不好的:

  • 同一类中的所有synchronized方法使用完全相同的锁,这会降低吞吐量
  • 任何人都可以访问该锁,包括其他类的成员。
  • 没有什么能够阻止我在另一个班级做这样的事情:

    MyClass c = new MyClass();
    synchronized(c) {
        ...
    }
    

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

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

    public class MyClass {
        private int instanceVar;
        private final Object lock = new Object();     // must be final!
    
        public void setInstanceVar() {
            synchronized(lock) {
                instanceVar++;
            }
        }
    }
    

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


    如果你想让这个类的线程安全,我会声明instanceVarvolatile ,以确保始终获得来自内存的最新值,并且还会使setInstanceVar() synchronized因为在JVM中,增量不是原子操作。

    private volatile int instanceVar =0;
    
    public synchronized setInstanceVar() { instanceVar++;
    
    }
    
    链接地址: http://www.djcxy.com/p/76267.html

    上一篇: What Cases Require Synchronized Method Access in Java?

    下一篇: Tips to prevent deadlocks in java