我有一个启动几个线程的函数(它是一个测试函数),其中一个线程会改变变量的状态。由于局部变量不能标记为volatile,我假设该方法中的多个线程将始终具有变量的更新状态。它是否正确?这是示例代码
public void someMethod() {
MutableBoolean mb = new MutableBoolean(false);
Thread t1 = new Thread() {
public void run() {
while (someCondition) {
if ( mb.getValue() ) {
...do something
}
}
}
}
t1.start();
Thread t2 = new Thread() {
public void run() {
if ( someCondition ) {
mb.setValue(true);
}
}
}
t2.start();
...wait for the threads to complete
}
答案 0 :(得分:6)
除非MutableBoolean在其set / get值方法中使用锁,否则它是一个原子操作,那么这不是线程安全的。
getValue可能正在读取值,而setValue正在更新它。你可以用布尔值来解决这个问题,但对于任何更复杂的类型,它可能会失败。
锁定对共享状态的访问以使其线程安全。
答案 1 :(得分:0)
要获得线程间可见性, volatile不是唯一的选择。任何同步(锁定)也可以。
在这种情况下,MutableBoolean可以是一个线程安全的类,这样就可以完成这项工作。
正如danben所说,MutableBoolean可能需要final
传递给函数。
您是否在发布之前在IDE中测试了代码?
答案 2 :(得分:0)
mb必须定义为final,否则代码将无法编译(匿名类只能访问声明范围的最终变量)。最终变量不能改变其值,因此从技术上讲,t1和t2总是会在mb处看到相同的值。出于这个原因,mb易失性的问题是无关紧要的。
你的问题不是关于mb对象本身的状态(MutableBoolean对象的字段所持有的值)。对于这些字段,您可以使用volatile和/或synchronized方法来确保线程安全。
答案 3 :(得分:0)
以前的海报是正确的,如果不使 mb 最终,这段代码将无法编译。对于引用类型,final意味着您无法更改变量引用的对象。 不意味着您无法更改该对象的状态。因此,您不能使 mb 引用 MutableBoolean 的不同实例,但 setValue(...)将一如既往地运行。应该同步 MutableBoolean.getValue()和 MutableBoolean.setValue(...),以便一个线程可以看到彼此的变化。
请注意,无法保证两个新线程中的语句将以何种顺序运行。或者t2或t1可能先运行,或者指令可能是交错的。
mb 是一个局部变量这一事实确实影响了这一点,但要求它是最终的。
有关此主题的明确字词,请参阅Java Concurrency in Practice。