当前位置: 首页 > 知识库问答 >
问题:

如果只有一个写线程,声明一个字段的易变性是否足够?

梁丘飞鸾
2023-03-14

考虑以下代码:

public class MyAtomicInteger {
    private volatile int value;

    public int get() {
        return value;
    }

    public void increment() {
        value++;
    }

}

在一次采访中,我被问到了以下问题:如果只有一个线程调用increment(),而多个线程可以调用get(),那么这个代码是线程安全的吗?

我知道,如果我们有多个写入线程,竞争条件可能会发生。然而,当每个读取线程中只有一个写入线程时,我们将按顺序获取值,即我们不会在1之后读取0,因为1的写入发生在第一次读取1之前,因此,在同一线程中的所有后续读取。这个推理是正确的,还是我漏掉了什么?

共有1个答案

陈畅
2023-03-14

通常,问题来自于读-修改-写的原子性,即。因为只有一个线程在做,所以只有一个线程在写值,其他线程在读值。

这就是易失性所提供的(线程所做更改的可见性),这就是所需要的。

当然,每个人都知道,设计这样的代码仍然不安全。有人添加了另一个线程,你的代码在你没有注意到的情况下被破坏了。

 类似资料:
  • 假设: 只有一个特定的线程设置了某个引用字段(不是长或双精度,所以写入它是原子的) 有任意数量的线程可能会读取同一个字段 稍微陈旧的读取是可以接受的(最多几秒钟) 在这种情况下,您需要挥发性或原子参考或类似的东西吗? 该条指出: 如果您严格遵守单一写入器原则,则不需要内存障碍。 这似乎表明,在我描述的情况下,你真的不需要做任何特殊的事情。 我做了一个测试,结果很奇怪: 有时运行this会输出“线程

  • 问题内容: 说我有一个全局对象: 有一个线程定期运行以从远程获取新编号并更新(仅写入): 并且有一个或多个线程随机使用此全局变量(仅读取): 您可以看到我不使用任何锁或对其进行保护,对吗?是否有可能引起问题的潜在问题? 更新: 就我而言,读取线程必须实时获取最新的值并不是很重要。我的意思是,如果有任何问题(由于缺少锁定/同步而导致)使一个读取线程错过了该值,那就没关系了,因为它将有机会尽快运行相同

  • 下面会对C语言、着色器语言ES GLSL、javascript语言和TypeScript语言声明变量的方式进行简单展示,这样可以更方便不同基础读者类比学习。 C语言 着色器语言ES GLSL和C语言有很多相似之处,如果你有一定的C语言基础,对于学习着色器语言也是有一定的帮助的。 // C语言声明一个整形变量并赋值10 int count = 10; // 改变变量值,重新赋值 count=20;

  • 在Flink中,像“平面地图”、“地图”等运算符称为任务,如果我将平面地图的并行度设置为30,那么这个任务有30个子任务。 现在,如果我只有一个插槽,它会在一个插槽中产生多个线程吗?还是每个插槽只有一个线程? Flink会在该插槽中简单地创建30个线程,还是使用类似线程池的东西? 以上不是一个恰当的例子。 假设在作业中我有操作符flatMap和map,它们都有并行度1,我只有一个插槽,这个插槽会创

  • 在实践中考虑java并发的片段 同一本书的摘录- 考虑易失性变量的一个好方法是想象它们的行为大致类似于上面清单中的同步整数类,用调用get和set来替换易失性变量的读写。然而,访问易失性变量不执行锁定,因此不会导致执行线程阻塞,这使得易失性变量成为比同步更轻量级的同步机制。 线程限制的一种特殊情况适用于可变变量。对共享的易失性变量执行读-修改-写操作是安全的,只要确保该易失性变量仅从单个线程写入。

  • 让我们假设这样: 存在单个ArrayList 列表由多个线程访问。线程可以添加元素并迭代所有元素。 所有访问都是外部同步的。因此两个线程不可能同时访问列表。 查看ArrayList源代码,我们可以看到size和elementData字段不是易变的: 另外,让我们看看add方法: 这样的事情会发生吗? 假设列表有4个元素。 线程A添加新元素。大小更新为5。 线程B添加新元素。Size被缓存,线程B看