假设我有两个线程更新一个对象,一个线程从该对象读取而没有同步。显然,这是运行条件。但是,我想知道变量本身是否只能部分写入。
public class CommonObject extends Object
{
static int memberVar=-1;
}
public class Input1Thread extends Thread
{
public void run()
{
while(true)
CommonObject.memberVar = 1
}
}
public class Input2Thread extends Thread
{
public void run()
{
while(true)
CommonObject.memberVar = 2;
}
}
public class OutputThread extends Thread
{
public void run()
{
while(true)
System.out.println("CommonObject.memberVar"+ CommonObject.memberVar);
}
}
我会假设打印出来的值也是2或1.但是,我想知道变量是否可能设置为中途?
我使用了原语作为一个例子,但如果不同的话,我也希望对象也能得到答案。
答案 0 :(得分:3)
这取决于变量的类型。
double
和long
s(Java中的两个64位类型)如果不是volatile
,则允许进行单词撕除,而所有其他类型(可能永远不会撕裂。单词撕裂会给你你担心的行为:一些字节来自旧值,其中一些是来自新值,而整体结果是一个既不是旧的也不是旧的值新。
这在JLS 17.7中指定:
出于Java编程语言内存模型的目的,对非易失性long或double值的单次写入被视为两个单独的写入:每个32位一半写入一次。这可能导致线程从一次写入看到64位值的前32位,而从另一次写入看到第二次32位。
volatile和long值的写入和读取始终是原子的。
对引用的写入和读取始终是原子的,无论它们是作为32位还是64位实现。
当然,引入数据竞赛引入了许多问题;但是你的问题专门针对单词撕裂,所以我只是在这里解决,除非要注意"只是因为你可以,并不意味着你应该这样做。"您应该小心分析您拥有的每个数据竞争,并证明它是良性的(因为它们中的一些 - 就像String.hashCode'它的值的缓存)。
答案 1 :(得分:0)
查看AtomicInteger类和线程上的java教程以获取示例。还有javadoc。
https://docs.oracle.com/javase/tutorial/essential/concurrency/
答案 2 :(得分:-1)
对于原语是安全的但对Object不安全。例如,对象A有两个变量int a,b,如果你试图在两个不同的线程中改变它们的值,你会发现两个线程的值都是可能有时会同时出现。