假设我有一个静态复杂对象,它由一个线程池定期更新,并在一个长时间运行的线程中或多或少地连续读取.对象本身总是不可变的,反映了最近的某种状态.
class Foo() { int a, b; }
static Foo theFoo;
void updateFoo(int newA, int newB) {
f = new Foo();
f.a = newA;
f.b = newB;
// HERE
theFoo = f;
}
void readFoo() {
Foo f = theFoo;
// use f...
}
Run Code Online (Sandbox Code Playgroud)
我至少不在乎我的读者是看到旧的还是新的Foo,但是我需要看到一个完全初始化的对象.IIUC,Java规范说没有HERE中的内存屏障,我可能会看到一个fb初始化但尚未提交到内存的对象.我的程序是一个真实世界的程序,它迟早会将内容提交到内存中,所以我不需要立即将新的值ofFoo提交到内存中(虽然它不会受到伤害).
您认为实现内存屏障最可读的方式是什么?如果需要,我愿意为了可读性而付出一点性能价格.我想我可以将赋值同步到Foo,这样可行,但是我不确定读取代码的人为什么这么做是非常明显的.我还可以同步新Foo的整个初始化,但这会引入更多实际需要的锁定.
你会如何编写它以使其尽可能可读?
对Scala版本的奖励荣誉:)
我正在重新阅读Java Concurrency In Practice,我不确定我是否完全理解有关不可变性和安全发布的章节.
这本书的内容是:
任何线程都可以安全地使用不可变对象而无需额外的同步,即使不使用同步来发布它们也是如此.
我不明白的是,为什么有人(有兴趣使他的代码正确)不安全地发布一些参考?
如果对象是不可变的,并且它是不安全地发布的,我理解获得对该对象的引用的任何其他线程将看到其正确的状态,因为由适当的不变性提供的保证(使用final字段等).
但是如果发布是不安全的,那么另一个线程可能仍然会null在发布之后看到或者之前的引用,而不是对不可变对象的引用,这对我来说似乎是没有人愿意的.
如果使用安全发布来确保所有线程都能看到新引用,那么即使对象实际上是不可变的(没有final字段,但也无法将它们静音),那么一切都是安全的.正如书中所说:
安全发布的有效不可变对象可以被任何线程安全地使用而无需额外的同步.
那么,为什么不变性(与有效不变性相比)如此重要?在什么情况下需要不安全的出版物?
synchronized 块让我使一组语句原子化,同时确保块退出和进入之间存在发生之前的关系。
我读到同步的最大成本是内存可见性保证,而不是锁争用。
假设我能够通过其他方式保证内存可见性:
如何做,而不需要创建的之前发生关系,那就是没有记忆效应的可视性我做一组语句原子的,synchronized/ Lock?
我尝试通过 CAS 在用户空间中实现锁定,但内置的性能远远超过它,并且 CAS 变量仍然发出内存障碍。
在这个例子中,没有内存可见性效果的互斥锁就足够了。
(release/acquire) int x; // Variable with release/acquire semantics
// release fence
synchronized (this) {
int y = x;
// acquire fence
// release fence
x = 5;
}
// acquire fence
Run Code Online (Sandbox Code Playgroud)
同一组栅栏被发射两次(通过互斥锁和x)。它会导致不必要的开销吗?
理论上没有记忆效应的锁是可能的吗?
没有记忆效应的锁实际上会更高效吗?
是否有内置的方法可以在 C++ 和/或 Java 中完成此操作?
如果没有,它可以用 C++ 和/或 Java 实现吗?
我正在阅读关于双重检查锁定的信息Effective Java.代码执行以下操作:
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) { // First check (no locking)
synchronized(this) {
result = field;
if (result == null) // Second check (with locking)
field = result = computeFieldValue();
}
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
它说使用result似乎不需要但实际上确保field只在已经初始化的常见情况下只读取一次.
但我不明白这一点.与if(field == null)直接做什么有什么区别?我不明白为什么if (result == null)会有所不同,更不用说如上所述了.
java concurrency multithreading synchronization effective-java
我有一个Thread-X,它每秒读取一个非易失性变量,这样做没有任何同步手段.
现在我想知道是否有某种方法可以修改Thread-Y上的非易失性变量,以便Thread-Y的写入(最终)在Thread-X上可见?
public class Test {
private static boolean double = 1; // this variable is
// strictly not volatile
public static void main(String args[]) {
new java.lang.Thread(new java.lang.Runnable() {
@Override
public void run() {
while (true) {
System.out.println(variable);
try {
java.lang.Thread.currentThread().sleep(1000);
} catch (java.lang.InterruptedException e) {
}
}
}
}).start(); // line 17
new java.lang.Thread(new java.lang.Runnable() {
@Override
public void run() {
// the task is to change variable to "2" such the write
// is (eventually) …Run Code Online (Sandbox Code Playgroud) 我写下了这段代码:
public class Main {
private boolean stopThread = false;
private int counter = 0;
public static void main(String[] args) throws InterruptedException {
final Main main = new Main();
new Thread(() -> {
try {
System.out.println("Start");
Thread.sleep(100);
System.out.println("Done");
main.stopThread = true;
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
while (!main.stopThread) {
main.counter++;
}
System.out.println(main.counter);
}).start();
System.out.println("End");
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行它时,while循环将永远运行。我对此有点挣扎,我对应用于此代码的优化 JIT 类型感到困惑。
首先我认为这是具有知名度的问题stopThread变量,但即使它是一个真正的while循环应该有点晚停比我分配stopThread到true时(从第1线程CPU缓存得到刷新到主存储器),所以事实并非如此。看起来像 JIT 硬编码false …
Volatile应该让线程从 RAM 中读取值,禁用线程缓存,如果没有volatile缓存,将启用线程不知道另一个线程所做的变量更改,但这不适用于以下代码。
为什么会发生这种情况,并且代码在使用和不使用volatile关键字时都一样?
public class Racing{
private boolean won = false; //without volatile keyword
public void race() throws InterruptedException{
Thread one = new Thread(()->{
System.out.println("Player-1 is racing...");
while(!won){
won=true;
}
System.out.println("Player-1 has won...");
});
Thread two=new Thread(()->{
System.out.println("Player-2 is racing...");
while(!won){
System.out.println("Player-2 Still Racing...");
}
});
one.start();
//Thread.sleep(2000);
two.start();
}
public static void main(String k[]) {
Racing racing=new Racing();
try{
racing.race();
}
catch(InterruptedException ie){}
}
Run Code Online (Sandbox Code Playgroud)
为什么这在有和没有volatile 的情况下表现相同?
java ×8
concurrency ×3
volatile ×2
atomic ×1
c++ ×1
caching ×1
immutability ×1
jit ×1
jvm ×1
performance ×1
scala ×1