java 变量本身是线程安全的吗?什么时候更新变量?

Are java variables themselves thread safe? When updating variables?

假设我有两个线程更新一个对象,一个线程在不同步的情况下读取该对象。很明显,这是运行条件。但是,我想知道变量本身是否只能部分写入。

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。但是,我想知道变量是否可能被设置了一半?

我以基元为例,但我希望答案也适用于对象,如果它不同的话。

查看 AtomicInteger class 和有关线程的 java 教程以获取示例。还有 javadoc.

https://docs.oracle.com/javase/tutorial/essential/concurrency/

它对原语是安全的,但对 Objects.for 例子不安全,对象 A 有两个变量 int a,b,如果你试图在两个不同的线程中改变它们的值,你会发现来自两个线程的值有时可能会同时出现。

这取决于变量的类型。

doubles 和 longs(Java 中的两种 64 位类型)如果不是 volatile,则允许​​分词,而所有其他类型(包括引用)可能永远不会撕裂。分词会给你带来你担心的行为:一些字节来自旧值,一些来自新值,总的结果是一个既不是旧值也不是新值的值。

这在JLS 17.7中指定:

For the purposes of the Java programming language memory model, a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64-bit value from one write, and the second 32 bits from another write.

Writes and reads of volatile long and double values are always atomic.

Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values.

当然,引入数据竞争会引入一大堆问题;但是你的问题是专门针对单词撕裂的,所以我只在这里解决这个问题,除了要注意 "just because you can, doesn't mean you should." 你应该小心分析你拥有的每个数据竞争并 prove 它是良性的(因为其中一些是——比如 String.hashCode 对其值的缓存)。