原子/易失性/同步如何在内部工作?
以下代码块之间有什么区别?
代码1
private int counter;
public int getNextUniqueIndex() {
return counter++;
}
Run Code Online (Sandbox Code Playgroud)
代码2
private AtomicInteger counter;
public int getNextUniqueIndex() {
return counter.getAndIncrement();
}
Run Code Online (Sandbox Code Playgroud)
代码3
private volatile int counter;
public int getNextUniqueIndex() {
return counter++;
}
Run Code Online (Sandbox Code Playgroud)
是否volatile以下列方式工作?是
volatile int i = 0;
void incIBy5() {
i += 5;
}
Run Code Online (Sandbox Code Playgroud)
相当于
Integer i = 5;
void incIBy5() {
int temp;
synchronized(i) { temp = i }
synchronized(i) { i = temp + 5 }
}
Run Code Online (Sandbox Code Playgroud)
我认为两个线程不能同时进入同步块...我是对的吗?如果这是真的那么如何atomic.incrementAndGet()工作没有synchronized …
如果我有一个在线程之间共享的对象,在我看来每个字段应该是final或者volatile,具有以下推理:
如果应该更改字段(指向另一个对象,更新原始值),那么该字段应该是volatile所有其他线程对新值进行操作.仅仅访问所述字段的方法的同步是不够的,因为它们可能返回缓存的值.
如果该领域永远不会改变,那就去做吧final.
但是,我找不到任何关于此的内容,所以我想知道这个逻辑是否有缺陷还是太明显?
当然编辑而不是易失性可能使用final AtomicReference或类似.
编辑,例如,请参阅get getter方法是Java中volatile的替代方法吗?
编辑以避免混淆:这个问题是关于缓存失效!如果两个线程对同一个对象进行操作,则可以缓存对象的字段(每个线程),如果它们未声明为volatile.如何保证缓存无效?
最后的编辑感谢@Peter Lawrey,他指出了JLS§17(Java内存模型).据我所知,它表明同步在操作之间建立了先发生关系,因此如果那些更新"发生在之前",则线程会看到来自另一个线程的更新,例如,如果非易失性字段的getter和setter是synchronized.
Java Concurrency in Practice解释了这个概念:
当一个线程在没有同步的情况下读取一个变量时,它可能会看到一个陈旧的值,但至少它会看到某个线程实际放置的值而不是某个随机值.这种安全保证称为超薄空气安全.
这种安全性是否很弱,因为它可能包含陈旧价值?
也许这个片段,at least it sees a value that was actually placed there by some thread than some random value是因为本书的上一个主题是JVM重新命令变量语句的可能性sharing variables without synchronization?
示例:根据重新排序:42或0可以打印出来.
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while(!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
Run Code Online (Sandbox Code Playgroud)
编辑 - 删除"请评论"评论.