我正在尝试使用异步CompletableFuture创建一个简单的示例,但是我看到了一些奇怪的行为。我的想法是,我启动2个异步期货,一个在设定的时间后激活一个布尔标志,另一个在线程1更改该标志后轮询该标志以释放该值。这是我的代码:
package completablefutures;
import java.util.concurrent.CompletableFuture;
public class CFMain throws InterruptedException {
public static void main(String... args) {
CF cf = new CF();
CompletableFuture.supplyAsync(cf::getCompletable).thenRun(() -> System.out.println("Post-future action"));
CompletableFuture.supplyAsync(cf::doSleep);
Thread.sleep(10000);
}
}
还有CF类:
package completablefutures;
public class CF {
private boolean valueIsSafe = false;
public boolean getCompletable() {
System.out.println("Fetching completable");
while(true) {
if(this.valueIsSafe) {
System.out.println("Completable fetched");
return true;
}
}
}
public boolean doSleep() {
System.out.println("Started sleeping");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.valueIsSafe = true;
System.out.println("Finished sleeping");
return true;
}
}
当我让程序运行时,它会显示以下内容:
可获取
开始睡觉
完成睡眠
以退出代码0结束的过程
即未来永远不会在分配的10秒内完成。那么这是怎么回事?
答案 0 :(得分:3)
要从多个线程访问valueIsSafe
,必须将此变量定义为volatile
。
private volatile boolean valueIsSafe = false;
使用volatile关键字将防止线程缓存此值,并强制它们在每次访问时读取原始内存。
答案 1 :(得分:1)
这是因为您没有使用线程安全的数据类型,可以更改代码以使用AtomicBoolean,这是使用AtomicBoolean的代码示例:
public class CF {
private AtomicBoolean valueIsSafe = new AtomicBoolean (false);
public boolean getCompletable() {
System.out.println("Fetching completable");
while(true) {
if(this.valueIsSafe.get()) {
System.out.println("Completable fetched");
return true;
}
//System.out.println("doing something");
}
}
public boolean doSleep() {
System.out.println("Started sleeping");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.valueIsSafe.set(true);
System.out.println("Finished sleeping");
return true;
}
}