Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:易失性足以使类线程安全?_Java_Thread Safety_Volatile - Fatal编程技术网

Java:易失性足以使类线程安全?

Java:易失性足以使类线程安全?,java,thread-safety,volatile,Java,Thread Safety,Volatile,我有一个关于Java中volatile语句的问题。请看这个示例: class Master { // Foo is a class with thread-safe methods public volatile Foo foo; } class Worker1 implements Runnable { protected Master master void run() { ... }; } class Worker2 implements Runnab

我有一个关于Java中volatile语句的问题。请看这个示例:

class Master {
    // Foo is a class with thread-safe methods
    public volatile Foo foo;
}

class Worker1 implements Runnable {
    protected Master master

    void run() { ... };
}

class Worker2 implements Runnable {
    protected Master master

    void run() { ... };
}
我们有两个工作线程,它们持有对同时运行的Master类对象的引用。在工作期间,两者都必须访问master.foo的方法。在某个时刻,主线程的Foo对象将被其中一个工作线程更改。现在我的问题是:volatile的使用是否使整个构造线程安全?我问这个问题是因为在一份声明中

但是,您可以指定一些原子操作:

  • 读取和写入是引用变量的原子[…]
原子操作不能交错,因此它们可以在不担心线程干扰的情况下使用

我只是想确保我正确理解了这一点


提前感谢:)

如果您只需要设置这个变量,那么是的,volatile就足够了。正如评论中所指出的,您需要volatile才能使更改可见(但是,如果没有volatile,您将不会有任何损坏的更新,就像使用long或double一样,请参见下文)

默认情况下,引用变量(对对象的引用)的读取和写入是原子的,对大多数基本类型(long和double除外)的读取和写入也是原子的

使用volatile,您可以确保对long和double类型的变量的读写也是原子的,在本例中不需要这样做


所以,是的,在这个例子中,这就足够了。但是,如果您打算发送更复杂的消息,请考虑使用java。UTI.Out.*/P>> P> <代码> Value确保线程读取变量将在该变量之前看到新值,而不是由另一个线程来设置。它不会看到存储在处理器缓存中的过时值


它是否使整个程序线程安全取决于程序做什么,它如何使用变量,以及Foo类是如何设计的。

在Java中,引用的读写始终是原子的,因此不存在看到处于某种半更新状态的引用的危险。如果这就是“线程安全”的意思,那么无论是否使用关键字,操作都是线程安全的

但是,
volatile
与原子性无关,它影响线程是否可以在本地缓存写操作<代码>易失性将强制写回主内存,并对其他线程可见。如果这就是线程安全的意思,那么是的,您需要这个关键字


volatile
本身不影响方法调用
foo
是否排除其他线程。如果这就是您的意思,您希望在另一个地方使用
synchronized

volatile是不够的

我相信这个例子说明了一种情况,即波动性是不够的:

共享对象:

public class Blammo
{
  public String kapow;
}
线程1中的代码:

Blammo blammo = new Blammo();
blammo.kapow = "zowie";
if ((blammo.kapow != null) && (blammo.kapow.isEmpty()))
{
  ...
}
线程2中的代码:

blammo.kapow = null;
线程1正在执行并执行(blammo.kapow!=null)。
线程1换出,线程2换入。
线程2执行(blammo.kapow=null)。
螺纹2换出,螺纹1换入。

线程1现在执行(blammo.kapow.isEmpty())并抛出空指针异常。

不一定没有volatile(简单的setter/getter将不会是线程安全的/可见的),如果没有volatile关键字,其他线程可能在任意长的时间内看不到更改。虽然这不会导致不一致,但可能不是期望的行为。volatile不仅仅对操作的原子性有影响。它还对值的可见性产生影响。使其非易失性可能使程序非线程安全。您所说的“更改”是什么意思?1.将创建
Foo
的新实例,2
Foo
的状态将被修改?很抱歉声明不清楚:这是关于更改引用,而不是对象本身。谢谢:)第二种情况是我关心的:)惊人的答案!容易理解!谢谢:)这也回答了我的问题:)您描述的
volatile
的语义在Java1.4之前是正确的。从1.5开始,volatile具有额外的角色。也就是说,它建立了before before关系(排序):假设
vl
volatile
,如果您写入
vl
,那么在写入
vl
之前发生的所有其他写入(在同一线程中)对其他线程也是可见的。读取
vl
可确保线程中所有后续读取(其他变量)的值与读取
vl
时相同。是的,我知道volatile的这种“级联”效应。我只是想解释一下volatile的基本功能。顺便说一句,依靠这种级联效应,事情比其他机制更不清晰、更脆弱,我不建议这样做。