在今天的工作中,我遇到了volatileJava中的关键字.我不太熟悉它,我发现了这个解释:
鉴于该文章解释了相关关键字的详细信息,您是否使用过它,或者您是否曾经看到过以正确方式使用此关键字的情况?
AtomicBoolean做什么,一个volatile布尔无法实现?
我阅读了一些关于该volatile关键字的文章,但我无法弄清楚它的正确用法.你能告诉我在C#和Java中它应该用什么吗?
在阅读JSR-133 Cookbook for Compiler Writers关于volatile的实现之后,特别是"与原子指令的交互"部分我认为读取volatile变量而不更新它需要LoadLoad或LoadStore屏障.在页面的下方,我看到LoadLoad和LoadStore在X86 CPU上实际上是无操作的.这是否意味着可以在x86上没有显式缓存失效的情况下完成易失性读取操作,并且正常变量读取速度快(忽略volatile的重新排序约束)?
我相信我不明白这一点.有人可以照顾我吗?
编辑:我想知道多处理器环境是否存在差异.在单CPU系统上,CPU可能会查看它自己的线程缓存,正如John V.所述,但在多CPU系统上,CPU必须有一些配置选项,这是不够的,主内存必须被击中,使得波动较慢在多CPU系统上,对吗?
PS:在我学习更多相关信息的路上,我偶然发现了以下很棒的文章,因为这个问题可能对其他人很有意思,我会在这里分享我的链接:
我读过" 什么时候在Java中使用'volatile'? "但我仍然感到困惑.我怎么知道何时应该标记变量volatile?如果我弄错了,要么在需要它的东西上省略volatile,要么在不需要的东西上放置volatile呢?在确定多线程代码中哪些变量应该是易变的时,有哪些经验法则?
重要编辑我知道在发生两个赋值的线程中 "发生在之前" 我的问题是,另一个线程是否可能读取"b"非空,而"a"仍为空.所以我知道如果你从与之前调用setBothNonNull(...)的线程相同的线程调用doIt(),那么它就不能抛出NullPointerException.但是如果一个人从另一个线程调用doIt()而不是调用setBothNonNull(...)的那个呢?
请注意,这个问题仅仅是对volatile关键字和volatile保证:这是不是对synchronized关键字(所以请不要回答"您必须使用同步"因为我没有任何问题要解决:我只是想了解volatile担保关于无序执行(或缺乏保证).
假设我们有一个包含两个volatileString引用的对象,它们被构造函数初始化为null,并且我们只有一种方法来修改两个String:通过调用setBoth(...)并且我们之后只能将它们的引用设置为非null引用(只允许构造函数将它们设置为null).
例如(这只是一个例子,毫无疑问):
public class SO {
private volatile String a;
private volatile String b;
public SO() {
a = null;
b = null;
}
public void setBothNonNull( @NotNull final String one, @NotNull final String two ) {
a = one;
b = two;
}
public String getA() …Run Code Online (Sandbox Code Playgroud) 我有一个缓存,我使用simeple HashMap实现.喜欢 -
HashMap<String,String> cache = new HashMap<String,String>();
Run Code Online (Sandbox Code Playgroud)
大多数时候使用此缓存来从中读取值.我有另一个方法重新加载缓存,在这个方法内部我基本上创建一个新的缓存,然后分配引用.据我所知,对象引用的赋值是Java中的Atomic.
public class myClass {
private HashMap<String,String> cache = null;
public void init() {
refreshCache();
}
// this method can be called occasionally to update the cache.
public void refreshCache() {
HashMap<String,String> newcache = new HashMap<String,String>();
// code to fill up the new cache
// and then finally
cache = newcache; //assign the old cache to the new one in Atomic way
}
}
Run Code Online (Sandbox Code Playgroud)
我理解如果我不将缓存声明为volatile,其他线程将无法看到更改,但对于我的用例将缓存中的更改传播到其他线程并且它们可以继续使用旧缓存并不是时间关键延长时间.
你看到任何线程问题吗?考虑到许多线程正在从缓存中读取,并且有时只重新加载缓存.
编辑 - 我的主要困惑是我不必在这里使用AtomicReference,因为赋值操作本身是原子的?
编辑 - 我理解为了使顺序正确,我应该将缓存标记为volatile.但是如果refreshCache方法被标记为synchronized,我不必将缓存设置为volatile,因为Synchronized块将负责排序和可见性?
我有两个主题:
主题:1
a = 1;
x = b;
Run Code Online (Sandbox Code Playgroud)
主题:2
b = 1
y = a
Run Code Online (Sandbox Code Playgroud)
这里a和b被声明为volatile.我不明白在a = 1之间如何创建"before-before"边缘; 和y = a; 在x = b之间; 和b = 1;
我知道通过使用volatile变量可以防止从线程缓存中读取过时值.但是,在订购之前,如何确保变量发生变化.
具体来说,我不明白这一点:
对每个后续读取相同字段之前发生对易失性字段的写入.
锄头有用吗?
我正在阅读B. Goetz Java Concurrency在实践中,现在我正处于section 3.5安全的出版物中.他说:
// Unsafe publication
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
Run Code Online (Sandbox Code Playgroud)
这种不正确的发布可能允许另一个线程观察部分构造的对象.
我不明白为什么可以观察到部分构造的子对象.假设构造函数Holder(int)不允许this转义.因此,构造的引用只能由调用者观察到.现在,正如JLS 17.7所述:
无论是否将它们实现为32位或64位值,对引用的写入和读取始终是原子的.
线程不可能观察到部分构造的对象.
我哪里错了?
在多线程环境中,线程如何看到"部分构造的对象"?我知道它不是线程安全的,因为多个线程可以创建多个实例.
class LazyInit
{ private static Resource resource = null;
public static getInstance()
{ if (resource == null) { resource = new Resource(); }
return instance;
}
}
Run Code Online (Sandbox Code Playgroud) 据我所知,如果我们将变量声明为volatile,那么它将不会存储在本地缓存中.每当线程更新值时,它都会更新到主存储器.因此,其他线程可以访问更新的值.
但是在下面的程序中,volatile和non-volatile变量都显示相同的值.
不会为第二个线程更新volatile变量.任何人都可以解释为什么testValue没有改变.
class ExampleThread extends Thread {
private int testValue1;
private volatile int testValue;
public ExampleThread(String str){
super(str);
}
public void run() {
if (getName().equals("Thread 1 "))
{
testValue = 10;
testValue1= 10;
System.out.println( "Thread 1 testValue1 : " + testValue1);
System.out.println( "Thread 1 testValue : " + testValue);
}
if (getName().equals("Thread 2 "))
{
System.out.println( "Thread 2 testValue1 : " + testValue1);
System.out.println( "Thread 2 testValue : " + testValue);
}
}
}
public class VolatileExample {
public …Run Code Online (Sandbox Code Playgroud) 即使经过这个,我仍然不清楚最终的使用如何导致安全发布在下面的代码中.有人能给出一个易于理解的解释.
public class SafeListener
{
private final EventListener listener;
private SafeListener()
{
listener = new EventListener()
{ public void onEvent(Event e)
{ doSomething(e); }
};
}
public static SafeListener newInstance(EventSource source)
{
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}
}
Run Code Online (Sandbox Code Playgroud)