为了账号安全,请及时绑定邮箱和手机立即绑定

无论线程如何,对象是否始终看到其最新的内部状态?

无论线程如何,对象是否始终看到其最新的内部状态?

慕标琳琳 2022-09-22 10:47:48

假设我有一个可运行的,它有一个简单的整数计数变量,每次可运行运行时都会递增。提交此对象的一个实例以在计划的执行程序服务中定期运行。


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);

在这里,对象正在访问不同线程内自己的内部状态(读取和递增)。此代码是线程安全的,还是当变量在其他线程中调度时,我们是否会丢失对变量的更新?count


查看完整描述

3 回答

?
万千封印

TA贡献1576条经验 获得超4个赞

无论线程如何,对象是否始终看到其最新的内部状态?

为了清楚这个问题及其答案的目的,一个物体不做任何事情;它只是记忆。线程是执行实体。说一个物体能看到什么东西是误导性的。它是执行对象状态的查看/读取的线程。

这在爪哇语中没有指定,但是

Executors.newScheduledThreadPool(5);

返回 .ScheduledThreadPoolExecutor

您的代码正在使用

executorService.scheduleWithFixedDelay(counter, 1, 1, TimeUnit.SECONDS);

调度线程池资源管理器#scheduleded与固定状态的 javadoc

提交一个周期性操作,该操作在给定的初始延迟之后首先启用,随后在一个执行终止和下一个执行开始之间的给定延迟下启用。

爪哇类进一步澄清

通过或不重叠计划的定期任务的连续执行。虽然不同的执行可能由不同的线程执行,但先前执行的效果发生在后续执行之前scheduleAtFixedRatescheduleWithFixedDelay

因此,保证 每个执行 都可以看到 在上一次执行递增后的值。例如,第三次执行将读取一个值,然后再执行其增量。Counter#runcountcount2

对于此特定用例,您不需要或任何其他附加的同步机制。volatile


查看完整回答
反对 回复 2022-09-22
?
胡说叔叔

TA贡献1494条经验 获得超8个赞

不,此代码不是线程安全的,因为在以 开始的不同线程中所做的增量之间没有任何发生任何关系。ScheduledExecutorService

要修复此问题,您需要将变量标记为 或切换到 或 。volatileAtomicIntegerAtomicLong

更新:

@BoristheSpider 如前所述,一般来说,在递增/递减的情况下,做一个变量是不够的,因为递增/递减本身不是原子的,并且同时从多个线程调用它将导致争用条件和错过更新。但是,在这种特殊情况下,保证(根据Javadoc)计划任务的重叠执行,因此即使在增量的情况下,也在此特定情况下也有效。volatilescheduleWithFixedDelay()volatile


查看完整回答
反对 回复 2022-09-22
?
噜噜哒

TA贡献1465条经验 获得超6个赞

不,此代码不是线程安全的,因为在访问 的不同线程之间的关系之前不会发生任何事件count



查看完整回答
反对 回复 2022-09-22

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信