我想写一个简单的线程安全类,可以用来设置或获取整数值。
最简单的方法是使用synchronized关键字:
public class MyIntegerHolder {
private Integer value;
synchronized public Integer getValue() {
return value;
}
synchronized public void setValue(Integer value) {
this.value = value;
}
}
我也可以尝试使用挥发性:
public class MyIntegerHolder {
private volatile Integer value;
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
}
带有易失性关键字线程安全的类吗?
考虑下面的事件顺序:
根据Java语言规范
但我不明白“1”怎么会出现在“2”之前,所以我怀疑“1”不会出现在“2”之前。
我怀疑线程C的读数可能是7或5。我认为带有volatile关键字的类不是线程安全的,以下顺序也是可能的:
我假设MyIntegerHolder with volatile不是线程安全的,对吗?
是否可以使用AtomicInteger创建线程安全的整数保持器:
public class MyIntegerHolder {
private AtomicInteger atomicInteger = new AtomicInteger();
public Integer getValue() {
return atomicInteger.get();
}
public void setValue(Integer value) {
atomicInteger.set(value);
}
}
?
以下是《Java并发性练习手册》的一部分:
“原子变量的读写与易失性变量具有相同的内存语义。”
编写线程安全MyIntegerHolder的最佳(最好是非阻塞)方式是什么?
如果你知道答案,我想知道你为什么认为它是正确的。它符合规格吗?如果是,怎么做?
Java语言规范的第17章定义了内存操作(如读取和写入共享变量)的“发生在”关系。只有在写操作发生在读操作之前,一个线程的写操作的结果才能保证对另一个线程的读操作可见。
参考:http://developer.android.com/reference/java/util/concurrent/package-summary.html
根据我的理解,3的意思是:如果你写(不是基于读取结果)/读取就可以了。如果写入(基于读取结果,例如增量)/读取不正常。因为volatile“不需要互斥锁定”
如果只需要对变量进行get/set,就可以像之前那样声明它为volatile。如果您检查AtomicInteger设置/获取的工作方式,您将看到相同的实现
private volatile int value;
...
public final int get() {
return value;
}
public final void set(int newValue) {
value = newValue;
}
但是你不能像这样简单地增加一个不稳定的场。这就是我们使用原子nteger.increment和获取或getAnd增量方法的地方。
关键字synchronized
表示如果线程A和线程B
想要访问整数
,它们不能同时访问。A告诉B等我做完。
另一方面,volatile
使线程更“友好”。他们开始互相交谈,一起工作来完成任务。因此,当B试图访问时,A将通知B在那一刻之前所做的一切。B现在意识到了这些变化,可以从A离开的地方继续工作。
在Java中,由于这个原因,您有原子
,它在封面下使用易失性
关键字,所以它们几乎在做同样的事情,但是它们节省了您的时间和精力。
你要找的是AtomicInteger,你说得对。对于您尝试执行的操作,这是最佳选择。
There are two main uses of `AtomicInteger`:
* As an atomic counter (incrementAndGet(), etc) that can be used by many threads concurrently
* As a primitive that supports compare-and-swap instruction (compareAndSet()) to implement non-blocking algorithms.
概括地回答你的问题
这取决于你需要什么。我不是说同步
是错误的,易失性
是好的,否则好Java的人早就删除了同步
。没有绝对的答案,有很多具体的案例和使用场景。
我的一些书签:
并发提示
核心Java并发
Java并发
使现代化
Java并发规范如下:
包java。util。同时发生的原子的
一个支持单变量无锁线程安全编程的小类工具包。
Instances of classes `AtomicBoolean`, `AtomicInteger`, `AtomicLong`, and `AtomicReference` each provide access and updates to a single variable of the corresponding type.
Each class also provides appropriate utility methods for that type.
For example, classes `AtomicLong` and AtomicInteger provide atomic increment methods.
The memory effects for accesses and updates of atomics generally follow the rules for volatiles:
get has the memory effects of reading a volatile variable.
set has the memory effects of writing (assigning) a volatile variable.
也从这里开始
Java编程语言volatile关键字:
(在Java的所有版本中)对易失性变量的读取和写入有全局顺序。这意味着每个访问易失性字段的线程将在继续之前读取其当前值,而不是(潜在地)使用缓存值。(但是,不能保证易失性读写与常规读写的相对顺序,这意味着它通常不是一个有用的线程构造。)
问题内容: 我是Go的新手,我需要创建一个线程安全的变量。我知道在Java中您只能使用关键字,但是似乎没有类似的东西存在。有什么方法可以同步变量? 问题答案: Java中的一种意思是仅允许单个线程(在任何给定时间)执行代码块。 在Go中,有很多构造可以实现该目标(例如互斥体,通道,等待组,中的原语),但是Go的谚语是: “不要通过共享内存进行通信;而是通过通信来共享内存。” 因此,不要锁定和共享变
我一直在浏览JCIP,作者说。。 线程限制的一种特殊情况适用于可变变量。对共享的易失性变量执行读-修改-写操作是安全的,只要您确保该易失性变量仅从单个线程写入 例如,实例计数被认为是一个复合操作(读取值,向其添加一个值,并更新值),声明计数为易失性不会使此操作原子化,因此线程安全在这里得不到保证!!我说得对吗??但是在这里,作者说如果我们确保只从单个线程写入易失性变量,我们就可以修复它。我不明白这
类OneValueCache是不可变的。但是我们可以更改变量缓存的引用。 但我不能理解为什么VolateCachedFactorizer类是线程安全的。 对于两个线程(线程A和线程B),如果线程A和线程B同时到达,那么两个线程A和B都将尝试创建OnEvalueCache。然后线程A到达而线程B同时到达。然后线程A将创建一个,它覆盖threadB创建的值(OneValueChange是不可变的,但是
问题内容: 我编写了一个单一的Kafka使用者(使用Spring Kafka),该使用者从单个主题中读取内容,并且是使用者组的一部分。消耗完一条消息后,它将执行所有下游操作,并移至下一个消息偏移。我将其打包为WAR文件,并且我的部署管道将其推送到单个实例。使用部署管道,我可以将该工件部署到部署池中的多个实例。 但是,当我希望多个消费者作为基础架构的一部分时,我无法理解以下内容: 实际上,我可以在部
问题内容: 给出以下代码: 线程类将定期(通过执行器每5分钟更新一次)myConfigData成员变量。myConfigData的设置是否在“外部”线程中是线程安全的(原子的),还是我必须将每个读写操作都同步到myConfigData变量? 编辑:问题不是ConcurrentHashMap是否是线程安全的(根据Javadoc),而是ConcurrentHashMap本身在myConfigData
我正在阅读JCIP,无法理解3.3.1中的以下语句, 对共享的易失性变量执行读-修改-写操作是安全的,只要可以确保仅从单个线程写入易失性变量。在本例中,您将修改限制在单个线程中,以防止出现争用情况,并且volatile变量的可见性保证确保其他线程看到最新的值。 即使挥发性变量只从单个线程写入,它怎么能不提高竞争条件?如果线程A在计数器为1时执行,线程B可以在计数器1写入内存之前进入,并获得的旧值1