Rac*_*hel 33 java multithreading boolean synchronize
我的建筑师总是说
永远不要在布尔上同步
我无法理解其中的原因,如果有人可以用一个例子来解释为什么它不是一个好的做法,我会非常感激. 参考样本代码
private Boolean isOn = false;
private String statusMessage = "I'm off";
public void doSomeStuffAndToggleTheThing(){
// Do some stuff
synchronized(isOn){
if(isOn){
isOn = false;
statusMessage = "I'm off";
// Do everything else to turn the thing off
} else {
isOn = true;
statusMessage = "I'm on";
// Do everything else to turn the thing on
}
}
}
Run Code Online (Sandbox Code Playgroud)
Gra*_*ray 62
我无法理解为什么我们应该"永远不会在布尔上同步"
您应始终synchronize
使用常量对象实例.如果您在分配的任何对象上进行同步(即将对象更改为新对象),则它不是常量,并且不同的线程将在不同的对象实例上进行同步.因为它们在不同的对象实例上同步,所以多个线程将同时进入受保护的块并且将发生竞争条件.对于同步等Long
,这是相同的答案Integer
.
// this is not final so it might reference different objects
Boolean isOn;
...
synchronized (isOn) {
if (isOn) {
// this changes the synchronized object isOn to another object
// so another thread can then enter the synchronized with this thread
isOn = false;
Run Code Online (Sandbox Code Playgroud)
更糟糕的是(正如@McDowell指出的那样)Boolean
通过autoboxing(isOn = true
)创建的任何对象都是与Boolean.TRUE
(或.FALSE
)相同的对象,它是ClassLoader
跨所有对象的单例.您的锁对象应该是它所使用的类的本地对象,否则您将锁定其他类可能在其他锁定情况下锁定的同一单例对象,如果它们犯同样的错误.
如果需要锁定布尔值,则正确的模式是定义private final
锁定对象:
private final Object lock = new Object();
...
synchronized (lock) {
...
Run Code Online (Sandbox Code Playgroud)
或者您也应该考虑使用AtomicBoolean
对象,这意味着您可能根本不需要synchronize
它.
private final AtomicBoolean isOn = new AtomicBoolean(false);
...
// if it is set to false then set it to true, no synchronization needed
if (isOn.compareAndSet(false, true)) {
statusMessage = "I'm now on";
} else {
// it was already on
statusMessage = "I'm already on";
}
Run Code Online (Sandbox Code Playgroud)
在你的情况下,因为看起来你需要用线程打开/关闭它然后你仍然需要synchronize
在lock
对象上设置布尔值并避免测试/设置竞争条件:
synchronized (lock) {
if (isOn) {
isOn = false;
statusMessage = "I'm off";
// Do everything else to turn the thing off
} else {
isOn = true;
statusMessage = "I'm on";
// Do everything else to turn the thing on
}
}
Run Code Online (Sandbox Code Playgroud)
最后,如果您希望statusMessage
从其他线程访问它,那么它应该被标记为volatile
除非您synchronize
在获取期间.
McD*_*ell 19
private Boolean isOn = false;
public void doSomeStuffAndToggleTheThing(){
synchronized(isOn){
Run Code Online (Sandbox Code Playgroud)
这是一个糟糕的主意.isOn
将引用Boolean.FALSE
公开可用的同一对象.如果任何其他编写错误的代码也决定锁定此对象,则两个完全不相关的事务将不得不等待彼此.
锁定在对象实例上执行,而不是在引用它们的变量上执行:
归档时间: |
|
查看次数: |
26760 次 |
最近记录: |