Java:易失性足以使类线程安全?
我有一个关于Java中volatile语句的问题。请看这个示例: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
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
的新实例,2Foo
的状态将被修改?很抱歉声明不清楚:这是关于更改引用,而不是对象本身。谢谢:)第二种情况是我关心的:)惊人的答案!容易理解!谢谢:)这也回答了我的问题:)您描述的volatile
的语义在Java1.4之前是正确的。从1.5开始,volatile具有额外的角色。也就是说,它建立了before before关系(排序):假设vl
是volatile
,如果您写入vl
,那么在写入vl
之前发生的所有其他写入(在同一线程中)对其他线程也是可见的。读取vl
可确保线程中所有后续读取(其他变量)的值与读取vl
时相同。是的,我知道volatile的这种“级联”效应。我只是想解释一下volatile的基本功能。顺便说一句,依靠这种级联效应,事情比其他机制更不清晰、更脆弱,我不建议这样做。