Ran*_*ion 12 java concurrency multithreading
假设我有一个带有简单整数计数变量的可运行对象,该变量在每次可运行对象运行时都会增加。提交此对象的一个实例,使其在预定的执行程序服务中定期运行。
class Counter implements Runnable {
private int count = 0;
@Override
public void run() {
count++;
}
}
Counter counter = new Counter();
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
executorService.scheduleWithFixedDelay(counter, 1, 1, TimeUnit.SECONDS);
Run Code Online (Sandbox Code Playgroud)
在这里,对象正在访问其在不同线程内部的内部状态(读取和递增)。此代码是线程安全的,还是count
在其他线程中计划变量时丢失变量的更新?
Sot*_*lis 11
一个对象是否总是看到其最新的内部状态而与线程无关?
为了清楚起见,在此问题及其答案中,一个对象什么也没做。这只是记忆。线程是执行实体。说物体看到了什么有误导性。正是线程正在查看/读取对象状态。
在Javadoc中未指定,但是
Executors.newScheduledThreadPool(5);
Run Code Online (Sandbox Code Playgroud)
返回ScheduledThreadPoolExecutor
。
您的代码正在使用
executorService.scheduleWithFixedDelay(counter, 1, 1, TimeUnit.SECONDS);
Run Code Online (Sandbox Code Playgroud)
状态的JavadocScheduledThreadPoolExecutor#scheduledWithFixedDelay
提交一个周期性操作,该操作将在给定的初始延迟之后首先启用,然后在给定的执行终止与下一个执行之间延迟一定的时间。
javadoc类进一步阐明
Successive executions of a periodic task scheduled via
scheduleAtFixedRate
orscheduleWithFixedDelay
do not overlap. While different executions may be performed by different threads, the effects of prior executions happen-before those of subsequent ones.
As such, each execution of Counter#run
is guaranteed to see the value of count
after it's been incremented by the previous execution. For example, the third execution will read a count
value of 2
before it performs its increment.
You don't need volatile
or any other additional synchronization mechanism for this specific use case.
不,此代码不是线程安全的,因为在以开头的不同线程中进行的增量之间没有任何事前关系ScheduledExecutorService
。
要修复它,您需要将变量标记为volatile
或切换到AtomicInteger
或AtomicLong
。
更新:
正如@BoristheSpider提到的那样,通常在递增/递减时创建变量volatile
是不够的,因为递增/递减本身不是原子的,并且同时从多个线程调用它会导致竞争条件和错过的更新。但是,在这种特殊情况下scheduleWithFixedDelay()
(根据Javadoc)保证了计划任务的执行会重叠,因此即使在递增的情况下volatile
也可以在这种特殊情况下工作。
归档时间: |
|
查看次数: |
393 次 |
最近记录: |