【发布时间】:2020-11-15 15:35:18
【问题描述】:
我有一个秒表,它使用内部单线程调度执行器运行指定的时间量(duration 参数):
public class StopWatch {
private final AtomicBoolean running = new AtomicBoolean();
private final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
private long lastTimeMillis;
private long durationMillis;
private long elapsedMillis;
private ScheduledFuture<?> future;
public void start(long duration, TimeUnit timeUnit) {
if (running.compareAndSet(false, true)) {
durationMillis = timeUnit.toMillis(duration);
lastTimeMillis = System.currentTimeMillis();
elapsedMillis = 0;
future = executor.schedule(this::tick, 0, TimeUnit.MILLISECONDS);
}
}
(...)
private void tick() {
long now = System.currentTimeMillis();
elapsedMillis += now - lastTimeMillis;
lastTimeMillis = now;
// do some stuff
if (elapsedMillis < durationMillis) {
future = executor.schedule(this::tick, 100, TimeUnit.MILLISECONDS);
return;
}
running.compareAndSet(true, false);
}
(...)
}
我的问题是:我是否会遇到这种方法的可见性问题(即在第一个周期完成后再次在 StopWatch 上执行.start() 之后)?
elapsedMillis 和 lastTimeMillis 在两个线程中更新,durationMillis 在第一个线程中更新并在第二个线程中读取,但它是按顺序发生的,并且计划任务在第一个线程完成更新字段后开始。我仍然不确定跳过这些领域的波动是否安全(可能不是)。
【问题讨论】:
标签: java multithreading thread-safety volatility