同步语句建立事前关联。但是我不确定细节。在http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package- summary.html中,可以阅读
发生监视器的解锁(同步块或方法退出)-在该监视器的每个后续锁定(同步块或方法入口)之前
我想知道我是否理解正确。因此,请看以下示例。假设有2个线程T1,T2共享类Data的相同实例数据和类Object的对象。现在,以下代码按给定的线程和顺序执行:
(1)T1: data.setValue("newValue"); (2)T1: synchronized(object){} (3)T2: synchronized(object){} (4)T2: String str=data.getValue();
因为(1)和(2)在同一线程中执行,所以具有hb(1,2)和模拟hb(3,4)。在(2)中是监视器的解锁,在(3)中是同一监视器的锁定,因此hb(2,3),因此hb(1,4)和str应该等于“ newValue”。那是对的吗?如果不是hb(2,3)应该是错误的,但是为什么呢?
编辑
因为需要数据类的详细信息来回答这个问题:
public class Data { private String value public void setValue(String newValue){ value=newValue; } public String getValue getValue(){ return value; } }
编辑2 明确表示,不能保证执行顺序。当一个人代替
(1*)T1: synchronized(object){data.setValue("newValue");} (2*)T2: synchronized(object){String str=data.getValue();}
也不能保证(1 )在(2 )之前被执行,但是如果我是对的,则可以保证在(2 )之后,如果(1 )在(2 )之前执行,则str =“ newValue” )。我想知道第一个例子是否也一样
因为(1)和(2)在同一线程中执行,所以具有hb(1,2)和模拟hb(3,4)。在(2)中是监视器的解锁,在(3)中是同一监视器的锁定,因此hb(2,3),因此hb(1,4)和str应该等于“ newValue”。那是对的吗?
是的,您的逻辑对于此特定方案是正确的。如果(且仅当)2在3then 之前执行hb(2, 3)。要理解为什么应该这样,请想象一个如下的线程过程:
2
3
hb(2, 3)
localState *= 2; synchronized(object) { sharedState = localState; }
尽管localState是 在 同步块 外部 计算的,但其他线程也必须看到此计算 也必须 看到的正确值sharedState。
localState
sharedState
但是,重要的是要了解没有理由期望您所要求的订单作为结果。例如,可以很容易地以这种方式执行:
(1)T1:data.setValue(“ newValue”); (3)T2:已同步(对象){} (4)T2:字符串str = data.getValue(); (2)T1:已同步(对象){}
这很不好,因为现在T1正在T2读取内存时,它正在不同步地写入内存中的某个位置。(T2甚至可以在写入发生的同时读取!)
T1
T2
要了解之前发生的一切,请想象这些线程正在同时运行(就像线程一样)并在以下时间轴上执行:
| T1 | T2 -------------------------------------------------- ----------- 1 | 同步(对象){} | 2 | data.setValue(“ newValue”); | 字符串str = data.getValue(); 3 | | 同步(对象){}
注意我如何调整这些假设的动作。
1
但 实际上第一个发生 在点2?T1是写还是T2读?
同步不能保证线程实际相对于彼此执行的顺序。相反,它与线程之间的 内存一致性 有关。
在点处2,因为没有同步,所以即使T1实际上是 先 写 后T2读,T2也可以自由查看内存中的 旧 值。因此,它可以 出现 是T2(2)发生过T1(2)。
T2(2)
T1(2)
从技术上讲,这意味着在同步之外,线程可以在CPU高速缓存而不是主内存中自由读取/写入。同步强制在主存储器中进行读/写。
现在有了第二个并发时间表:
T1 | T2 -------------------------------------------------- ---------- 同步(对象){| 同步(对象){ data.setValue(“ newValue”); | 字符串str = data.getValue(); } | }
尽管我们不能保证哪个线程首先获取锁,但是我们可以保证内存访问将是一致的。我们还保证他们的行动不会重叠,这在第一个时间表中是可能的。