考虑一下volatile int sharedVar.我们知道JLS为我们提供了以下保证:
w其写入值之前i以sharedVar程序顺序happens-before写入动作;i通过w happens-before的成功读取i从sharedVar由读取线程r;i从sharedVar由读线程r happens-before的所有后续行动r的程序顺序.然而,仍有给出没有挂钟时间的保证,当读线程将观察值i.一个完全不会让读取线程看到该值的实现仍然符合此契约.
我已经考虑了一段时间,我看不到任何漏洞,但我认为必须有.请指出我的推理漏洞.
我试图理解CompletableFutureJava 8 如何与Java内存模型交互.在我看来,对于程序员的理智,理想情况下应该成立:
CompletableFuture - 在执行任何java.util.concurrent文档中有一条说明:
在提交
Runnable到执行之前的线程中的操作Executor- 在执行开始之前.同样的Callables提交给ExecutorService.
这表明第一个属性为true,只要完成未来的线程执行完成依赖阶段或将其提交给Executor.另一方面,在阅读CompletableFuture文档后,我不太确定:
为非异步方法的依赖完成提供的动作可以由完成当前的线程执行
CompletableFuture,或者由完成方法的任何其他调用者执行.
这让我想到了我的问题:
CompletableFuture?附录:
在具体示例中,请考虑以下代码:
List<String> list1 = new ArrayList<>();
list1.add("foo");
CompletableFuture<List<String>> future =
CompletableFuture.supplyAsync(() -> {
List<String> list2 = new ArrayList<>();
list2.addAll(list1);
return list2;
});
Run Code Online (Sandbox Code Playgroud)
能够保证所有的加入"foo"到list1是可见的lambda函数?是否保证添加 …
java java.util.concurrent java-memory-model java-8 completable-future
java multithreading synchronization thread-safety java-memory-model
根据Java Memory Model,只要执行结构良好,指令就可以重新排序.
所以我想知道,以下代码是否可能产生以下输出?
[代码] [在同一个主题中]
long a = System.currentTimeMillis();
long b = System.currentTimeMillis();
long c = System.currentTimeMillis();
Run Code Online (Sandbox Code Playgroud)
[输出]
a == 10, b == 20, c == 15
Run Code Online (Sandbox Code Playgroud)
如果不可能,那么JVM /实现会做些什么来防止这种情况发生?
谁能告诉我这个类是否是线程安全的?
class Foo {
private final Map<String,String> aMap;
public Foo() {
aMap = new HashMap<String, String>();
aMap.put("1", "a");
aMap.put("2", "b");
aMap.put("3", "c");
}
public String get(String key) {
return aMap.get(key);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:我不能澄清这个问题.根据JMM FAQ:
应提供初始化安全性的新保证.如果一个对象被正确构造(这意味着对它的引用在构造期间不会被转义),那么看到对该对象的引用的所有线程也将看到在构造函数中设置的最终字段的值,而不需要同步.
这让我把这个集合混淆为aMap aMap = new HashMap<String, String>();.所以其他线程可以看到这些
aMap.put("1", "a");
aMap.put("2", "b");
aMap.put("3", "c");
Run Code Online (Sandbox Code Playgroud)
或不 ?
编辑:我发现这个问题与我的问题完全不同
JMM中的因果关系似乎是其中最令人困惑的部分.我有几个关于JMM因果关系的问题,并允许并发程序中的行为.
据我了解,目前的JMM总是禁止因果关系循环.(我对吗?)
现在,根据JSR-133文档,第24页,图16,我们有一个例子,其中:
原来 x = y = 0
线程1:
r3 = x;
if (r3 == 0)
x = 42;
r1 = x;
y = r1;
Run Code Online (Sandbox Code Playgroud)
线程2:
r2 = y;
x = r2;
Run Code Online (Sandbox Code Playgroud)
直觉上,r1 = r2 = r3 = 42似乎不可能.但是,它不仅被提及,而且在JMM中也被"允许".
对于这种可能性,我无法理解的文件中的解释是:
编译器可以确定分配给的唯一值
x是0和42.从那以后,编译器可以推断出,在我们执行的时候r1 = x,我们刚刚执行了42的写入x,或者我们刚刚读过x和看过价值42.在任何一种情况下,读取x价值42 是合法的.然后可以r1 = x改为r1 = 42; 这将允许y = r1转换为y = 42更早并执行,从而导致相关行为.在这种情况下,y首先提交写入.
我的问题是,它真的是什么样的编译器优化?(我是编译器无知的.)由于42只被写入有条件,当if …
java concurrency compiler-optimization causality java-memory-model
从Java并发实践中的书:
要安全地发布对象,必须同时使对象的引用和对象的状态对其他线程可见.正确构造的对象可以通过以下方式安全发布:
从静态初始化程序初始化对象引用
将对它的引用存储到volatile字段或AtomicReference中
将对它的引用存储到正确构造的对象的最终字段中
将对它的引用存储到由
锁正确保护的字段中.
我的问题是:
volatile方法和final方法在安全发布对象方面的区别感兴趣.this引用转义).但他们为什么再次提到正确构造的物体呢?以下代码示例显示了一种常见方法,用于演示由于缺少发生之前关系而导致的并发问题。
private static /*volatile*/ boolean running = true;
public static void main(String[] args) throws InterruptedException {
new Thread() {
@Override
public void run() {
while (running) {
// Do nothing
}
}
}.start();
Thread.sleep(1000);
running = false;
}
Run Code Online (Sandbox Code Playgroud)
如果running是volatile,程序保证在大约一秒后终止。但是,如果running不是volatile,则根本无法保证程序终止(因为在running这种情况下没有发生之前关系或保证变量更改的可见性),而这正是我的测试中发生的情况。
根据JLS 17.4.5,人们还可以通过写入和读取另一个volatile变量来强制执行发生前关系running2,如以下代码示例所示。
private static boolean running = true;
private static volatile boolean running2 = true;
public static void main(String[] args) throws InterruptedException {
new Thread() …Run Code Online (Sandbox Code Playgroud) java multithreading volatile java-memory-model happens-before
我最近在我的代码库中找到了这个gem:
/** This class is used to "publish" changes to a non-volatile variable.
*
* Access to non-volatile and volatile variables cannot be reordered,
* so if you make changes to a non-volatile variable before calling publish,
* they are guaranteed to be visible to a thread which calls syncChanges
*
*/
private static class Publisher {
//This variable may not look like it's doing anything, but it really is.
//See the documentaion for this class.
private volatile AtomicInteger sync …Run Code Online (Sandbox Code Playgroud) 我目前正在尝试了解有关最终字段的 JLS 部分。
为了更好地理解 JLS 中的文本,我还在阅读Jeremy Manson(JMM 的创建者之一)撰写的The Java Memory Model。
该论文包含让我感兴趣的示例:如果o具有 final 字段的对象对另一个线程可见t两次:
o的构造函数完成之前首先“不正确地”o的构造函数完成后的下一个“正确”然后即使仅通过“正确”发布的路径访问它,也t可以看到半构造的o。
这是论文中的部分:
图 7.3:简单最终语义示例
f1 是最后一个字段;它的默认值为 0
主题 1 主题 2 主题 3 Run Code Online (Sandbox Code Playgroud)o.f1 = 42; p = o; freeze o.f1; q = o; Run Code Online (Sandbox Code Playgroud)r1 = p; i = r1.f1; r2 = q; if (r2 == r1) k = r2.f1; Run Code Online (Sandbox Code Playgroud)r3 = q; j = r3.f1;我们假设 r1、r2 和 …