synchronized语句建立之前发生的关系。但我不确定细节。 在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&#34 ;。那是对的吗?如果不是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 *)之后有一个str =" newValue" if(1 *)之前执行(2 *)。我想知道第一个例子是否同样适用
答案 0 :(得分:1)
因为(1)和(2)在同一个线程中执行,一个有hb(1,2)和模拟hb(3,4)。在(2)中是监视器的解锁和(3)同一监视器的锁定,因此hb(2,3),因此hb(1,4)和str应该等于“newValue”。这是对的吗?
是的,您的逻辑对于此特定方案是正确的。如果{且仅当} 2
在3
之前执行,则hb(2, 3)
。要理解它应该是什么,想象一下如下的线程进程:
localState *= 2;
synchronized(object) {
sharedState = localState;
}
虽然localState
计算在之外的同步块,但是其他线程必须看到此计算也看到{{的正确值1}}。
然而,重要的是要理解没有理由期待您所询问的订单作为结果。例如,执行这种方式很容易:
(1)T1: data.setValue("newValue"); (3)T2: synchronized(object){} (4)T2: String str=data.getValue(); (2)T1: synchronized(object){}
这很糟糕,因为现在sharedState
正在写入内存中的某个位置而没有同步,而T1
即将读取它。 (T2
甚至可以在写入的同时读取!)
要了解发生了什么 - 之前就是这样,相反,想象这些线程并发运行(如线程那样)并在以下时间轴下执行:
| T1 | T2 ------------------------------------------------------------- 1 | synchronized(object){} | 2 | data.setValue("newValue"); | String str=data.getValue(); 3 | | synchronized(object){}
请注意我如何对齐这些假设行为。
T2
点,1
获取锁定并将其释放。T1
点,2
同时执行写入T1
执行读取。T2
点,3
获取锁定并将其释放。但在T2
点实际上首先发生? 2
写或T1
读了?
同步不保证线程实际相对于彼此执行的顺序。相反,它是关于线程之间的内存一致性。
在T2
点,因为没有同步,即使2
实际上在 T1
读取之前实际写了,T2
也是可以自由查看内存中的旧值。因此,T2
之前T2(2)
可能出现。
从技术上讲,这意味着在同步之外,线程可以在CPU缓存而不是主内存中自由读/写。同步强制主存储器中的读/写。
现在有了第二个并发时间轴:
T1 | T2 ------------------------------------------------------------ synchronized(object){ | synchronized(object){ data.setValue("newValue"); | String str=data.getValue(); } | }
虽然我们无法保证哪个线程首先获得锁定,但我们确保内存访问保持一致。我们也保证他们的行动不会重叠,这在第一个时间表中是可能的。
T1(2)
首先获得锁定,则可以保证T1
的同步操作看起来好像在T1
的操作之前发生。 (T2
肯定会在T1
读之前写。)T2
首先获得锁定,则可以保证T2
的同步操作看起来好像在T2
的操作之前发生。 (T1
肯定会在T1
读后写。)答案 1 :(得分:0)
没有。在语句3之前,语句2将始终执行或发生并不是必需的。线程2可能会在对象上获取监视器,因此语句3将在语句2之前发生。
您无法控制哪个线程实际上会获取对象的监视器而您无法预测。
答案 2 :(得分:0)
不是那么简单。它还取决于data.setValue
和data.getValue
实际做了什么。这些方法对于并发(非同步)调用是否安全?
在一个人为的例子中,如果数据由HashMap
支持,并且多个线程同时调用各种set方法,则可以lead to an infinite loop。
简而言之,您只能保证执行的顺序。你对set和get之间的内存可见性有一些有限的保证,但是没有并发调用来设置或得到任何潜在的副作用。