Java 使用字段的每个方法中的同步块
这似乎是一个非常常见的问题,尽管我没有找到一个。假设我有一段代码:Java 使用字段的每个方法中的同步块,java,synchronized,Java,Synchronized,这似乎是一个非常常见的问题,尽管我没有找到一个。假设我有一段代码: 公共类MyClass{ 另一类私人领域; 公共无效变更单(另一类新单){ //这里有几行代码 已同步(mField){ mField=newOne; } //这里有几行代码 } 公共无效变更二(另一类新二){ //这里有几行代码 mField=newTwo; //这里有几行代码 } } 假设从不同的线程调用changeOne()和changeTwo()。在changeOne()中有一个同步块足以保护mField不被change
公共类MyClass{
另一类私人领域;
公共无效变更单(另一类新单){
//这里有几行代码
已同步(mField){
mField=newOne;
}
//这里有几行代码
}
公共无效变更二(另一类新二){
//这里有几行代码
mField=newTwo;
//这里有几行代码
}
}
假设从不同的线程调用
changeOne()
和changeTwo()
。在changeOne()
中有一个同步块足以保护mField
不被changeTwo()
更改吗?或者我需要显式地将mField
更改为synchronized
块的每个位置包装起来?(请留下同步方法和其他方法)。您需要使用同步块(或)同步方法显式同步对mField
的所有修改。否则,通过一次执行change2,可以有多个线程更改mField
编辑:正如Tedd Hopp所建议的,若变量不是易失性的,那个么读取也需要同步,并且您得到的锁应该在同一个对象上 您需要使用同步块(或)同步方法将所有修改显式同步到
mField
。否则,通过一次执行change2,可以有多个线程更改mField
编辑:正如Tedd Hopp所建议的,若变量不是易失性的,那个么读取也需要同步,并且您得到的锁应该在同一个对象上 不,不是这样,两个线程必须尝试获得相同的锁,然后如果线程A获得了锁,那么第一个线程B将被阻塞,直到A释放它。锁可以是A和B共同的任何对象,最典型的情况是
public class MyClass {
private AnotherClass mField;
public synchronized void changeOne(AnotherClass newOne) {
...
}
public synchronzied void changeTwo(AnotherClass newTwo) {
...
}
在这种情况下,此
用作锁。这几乎相当于
同步方法更紧凑,同步块更灵活。使用synchronized block可以锁定任何对象,而使用synchronized method可以在
this
上隐式锁定,或者对于class
上的静态方法隐式锁定。不,不是这样,两个线程都必须尝试获得相同的锁,如果线程A获得了锁,那么第一个线程B将被锁定,直到A释放它。锁可以是A和B共同的任何对象,最典型的情况是
public class MyClass {
private AnotherClass mField;
public synchronized void changeOne(AnotherClass newOne) {
...
}
public synchronzied void changeTwo(AnotherClass newTwo) {
...
}
在这种情况下,此
用作锁。这几乎相当于
同步方法更紧凑,同步块更灵活。使用synchronized block可以锁定任何对象,而使用synchronized method可以隐式锁定
this
或class
上的静态方法,因此changeTwo不会检查mField是否在没有同步块的情况下锁定?@AndreyErmakov:这是正确的。每个线程在执行方法时都会创建一个堆栈,因此一个线程不知道其他线程的更改,除非您同步。@Nambari您的意思是当两个线程同时执行changeTwo
时,或者两个线程,其中第一个线程执行changeOne
,第二个线程执行changeTwo
?仅同步修改是不够的。如果读取未同步且变量未声明为volatile,则读取线程可能使用过时值的线程本地副本,即使在修改变量后同步块退出后也是如此。请参阅Brian Goetz文章中的模式5。@WaleryStrauch:两种情况都有。所以changeTwo不会检查mField是否在没有同步块的情况下被锁定?@AndreyErmakov:这是正确的。每个线程在执行方法时都会创建一个堆栈,因此一个线程不知道其他线程的更改,除非您同步。@Nambari您的意思是当两个线程同时执行changeTwo
时,或者两个线程,其中第一个线程执行changeOne
,第二个线程执行changeTwo
?仅同步修改是不够的。如果读取未同步且变量未声明为volatile,则读取线程可能使用过时值的线程本地副本,即使在修改变量后同步块退出后也是如此。请参阅Brian Goetz文章中的模式5。@WaleryStrauch:两种情况都有。同步方法有什么问题?我们要留下的“其他”是什么?@TedHopp我的意思是,在产生这个问题的真正代码段中,我只处理同步的块,而不是同步的方法,易变的字段。好吧,不管你做什么,你都需要在共享锁对象上同步,不在正在修改的变量上!(控制对成员字段访问的最明显的方便锁定对象是此
,这基本上就是同步方法所做的。)@TedHopp为什么不在变量上?不在变量上,因为变量更改后,您不再在变量上同步;您在以前的变量上进行了同步。其他线程将无法在您锁定的对象上同步,因此实际上不会进行同步。同步方法有什么问题?我们要留下的“其他”是什么?@TedHopp我的意思是,在产生这个问题的真正代码段中,我只处理同步的块,而不是同步的方法,易变的字段。好吧,不管你做什么,你都需要在共享锁对象上同步,不在正在修改的变量上!(控制对成员字段访问的最明显的方便锁定对象是this
,这基本上就是同步方法所做的。)@TedHopp为什么不在变量上?不在变量上,因为变量更改后,