【发布时间】:2016-10-16 09:56:52
【问题描述】:
我正在尝试以特定顺序以三个不同的Threads 在单个实例上执行三个方法。也就是说methodA 应该在methodB 之前调用,methodB 在methodC 之前调用。
我最初尝试了一种不复杂的代码方法:
public void testFoo()
{
Foo foo = new Foo();
ExecutorService service = Executors.newFixedThreadPool(3);
service.submit(() -> foo.callMethodB());
service.submit(() -> foo.callMethodC());
service.submit(() -> foo.callMethodA());
service.shutdown();
}
class Foo
{
boolean methodAcompleted;
boolean methodBcompleted;
void callMethodA()
{
this.methodA();
methodAcompleted = true;
}
void callMethodB()
{
while (true)
{
if (methodAcompleted)
{
this.methodB();
methodBcompleted = true;
break;
}
}
}
void callMethodC()
{
while (true)
{
if (methodBcompleted)
{
this.methodC();
break;
}
}
}
void methodA()
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method A completed!");
}
void methodB()
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method B completed!");
}
void methodC()
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method C completed!");
}
}
我得出以下奇怪的观察结果:
1) 执行上面的代码只打印出"Method A completed!"。即使我将布尔变量更改为static,我也会得到相同的结果。
2)如果我将布尔变量更改为volatile,那么所有语句都以正确的顺序打印:
"Method A completed!"
"Method B completed!"
"Method C completed!"
据我所知,这是意料之中的,因为不能保证(或不可能?)Thread 会被同一实例上的另一个 Thread 操作通知更改。即使在static 变量上执行更改也是如此吗?
3) 当我从让它们运行的方法中删除延迟 Thread.sleep() 时,这会变得很奇怪:
void methodA()
{
System.out.println("Method A completed!");
}
void methodB()
{
System.out.println("Method B completed!");
}
void methodC()
{
System.out.println("Method C completed!");
}
在这种情况下,语句总是以正确的顺序打印,就像在情况 2 中一样:
"Method A completed!"
"Method B completed!"
"Method C completed!"
Thread 可以/应该看到另一个 Thread 作用于同一变量而不是 volatile 的变化吗? case 1 和 case 3 之间的不同行为/结果的解释是什么?
更新:
我认为如果上述方法必不可少,最好的解决方案是使用AtomicBoolean而不是原语:
class Foo {
AtomicBoolean methodAcompleted = new AtomicBoolean(false);
AtomicBoolean methodBcompleted = new AtomicBoolean(false);
...
}
我相信atomic types 的目的是保证在这些情况下的行为一致。
【问题讨论】:
标签: java multithreading volatile