Java同步方法锁定对象,还是方法?

如果我在同一类中有 2 个同步方法,但每个方法访问不同的变量,那么 2 个线程可以同时访问这 2 个方法吗?锁定是发生在对象上,还是像同步方法中的变量一样具体?

例:

class X {

    private int a;
    private int b;

    public synchronized void addA(){
        a++;
    }

    public synchronized void addB(){
        b++;
    }

}

是否可以同时有 2 个线程访问执行类 X 的同一实例?x.addA(x.addB()


答案 1

如果将方法声明为已同步(就像通过键入执行的那样),则会对整个对象进行同步,因此两个线程从同一对象访问不同的变量无论如何都会相互阻塞。public synchronized void addA()

如果一次只想在一个变量上进行同步,以便两个线程在访问不同的变量时不会相互阻塞,则可以在块中分别对它们进行同步。如果 和 是对象引用,则使用:synchronized ()ab

public void addA() {
    synchronized( a ) {
        a++;
    }
}

public void addB() {
    synchronized( b ) {
        b++;
    }
}

但是由于它们是原始的,你不能这样做。

我建议你改用AtomicInteger

import java.util.concurrent.atomic.AtomicInteger;

class X {

    AtomicInteger a;
    AtomicInteger b;

    public void addA(){
        a.incrementAndGet();
    }

    public void addB(){ 
        b.incrementAndGet();
    }
}

答案 2

在方法声明上同步的是语法糖,用于此:

 public void addA() {
     synchronized (this) {
          a++;
     }
  }

在静态方法上,它是语法糖:

 ClassA {
     public static void addA() {
          synchronized(ClassA.class) {
              a++;
          }
 }

我认为,如果Java设计人员当时知道现在对同步的理解,他们就不会添加语法糖,因为它往往会导致并发的不良实现。