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为什么不在变量上?不在变量上,因为变量更改后,