在什么情况下需要同步访问实例成员?我理解,对类的静态成员的访问总是需要同步 - 因为它们在类的所有对象实例之间共享.
我的问题是,如果我不同步实例成员,我什么时候会不正确?
例如,如果我的班级是
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
块中,我持有所有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++; } } }
或者,您可以使用java.util.concurrent.Lock
接口和java.util.concurrent.locks.ReentrantLock
实现来实现基本相同的结果(事实上,它在Java 6上是相同的).
这取决于您是否希望您的类是线程安全的.大多数类不应该是线程安全的(为简单起见),在这种情况下,您不需要同步.如果您需要它是线程安全的,您应该同步访问或使变量volatile.(它避免了其他线程获得"陈旧"数据.)