静态同步方法和非同步静态方法混淆

时间:2013-08-09 08:30:13

标签: java multithreading

我有一点困惑。请看下面的代码。

public class ThreadDemo {
  //non-static synchronized method
  synchronized void a(){
   actBusy();
  }

  //static synchronized method
  static synchronized void b(){
    actBusy();
  }

  //static method
  static void actBusy(){
    try{
      Thread.sleep(1000);
    }
    catch(InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static void main(String[] args){
    final ThreadDemo x = new ThreadDemo();
    final ThreadDemo y = new ThreadDemo();
    Runnable runnable = new Runnable() {
      public void run() {
         int option = (int) (Math.random() * 4);
         switch (option){
           case 0: x.a();
             break;
           case 1: x.b();
             break;
           case 2: y.b();
             break;
           case 3: y.b();
             break;
         }
      }
    }   ;
    Thread t1 = new Thread(runnable);
    Thread t2 = new Thread(runnable);
    t1.start();
    t2.start();
  }
}

我确信可以调用此序列。

x.a() //in Thread-1
y.b() //in Thread-2

虽然我仍然有一点混淆,但我们可以很容易地看到x.a()也调用actBusy()方法 这是一个 静态方法。方法b()是一个调用非同步的静态同步方法 静态方法。当thread-2获得类级别锁定时,为什么从Thread-1调用actBusy() 没被封锁?

我只是在逻辑上混淆,如果一个线程得到一个类级锁定,那个类别 非同步静态方法保持打开状态,可以从其他方法(实例方法)调用。为什么呢?

4 个答案:

答案 0 :(得分:4)

  

那么为什么不阻止来自Thread-1的actBusy()的调用?

由于您的actBusy方法未同步。即使您获得了类级别锁定,也可以调用非同步的静态方法。

将方法标记为synchronized的目的是启用锁定。只有声明为synchronized的方法才是这些锁的主题。因此,如果您获得了一个锁(假设类级别锁定),则任何non-synchronized方法都像以前一样起作用,并且不知道正在获取锁定。这允许您决定哪些方法需要阻止,哪些方法不需要。

答案 1 :(得分:3)

static synchronized方法锁定类对象,而非静态synchronized方法锁定实例对象({{ 1}}) - 因此可以同时调用这两个方法,一个线程将运行1而另一个线程运行第二个。

但请注意,您的代码中没有race condition可用,因为竞争条件需要写入,而这些方法中不存在此类。

答案 2 :(得分:2)

actBusy()本身并未同步,但调用方法是。

因此,线程1不会阻塞,因为它获取this对象上的锁定而其他线程没有锁定this,因此它可以毫无问题地调用它。

这是因为non-static synchronized方法锁定了this当前实例而不是class对象。

x.a()抓取当前实例的锁,即x,其他任何线程都无法进入a()的方法x,直到当前线程释放锁。

线程1 - > x.a() //acquires lock and holds it

线程2 ---> x.a() //blocks here until Thread 1 releases lock on x

修改

Class Object != Instance 

因此根据JMM,它们是不同的对象,并且两个线程不会相互干扰。所以它允许你调用它。

编辑2:

  

为什么它允许调用其他静态方法?它背后的任何逻辑?

假设:

public static synchronized int statefulMethod(){
    //this should be protected
}

public static int nonStatefulMethod(){
    //Just returns a static value such as 5
    //so this is thread safe as it does not have any state
}

public static synchronized int otherStatefulMethod(){
    //this should also be thread safe
}

因此,如果线程1在方法statefulMethod()中,它有一些共享状态要保护,那么它使用类级别锁定。现在线程2调用nonStatefulMethod()然后它不应该逻辑阻塞,因为该方法是线程安全的,并且没有必要在此处阻止该线程

现在,如果线程3在线程1持有类锁定时调用otherStatefulMethod(),则线程3必须等待,因为该方法也是static-synchornized

答案 3 :(得分:1)

锁定对象不是分层的。因此,获取类本身的锁定并不会取代对类实例的锁定。它们是单独的锁定对象,只会阻止尝试锁定同一对象的代码。

因此,如果一个线程进入静态同步方法,那么唯一将被阻塞的线程也是那些试图在同一个类上输入静态同步方法的线程。仅仅尝试进入非静态同步方法的线程不受影响 - 它们仅与试图在同一对象实例上输入非静态同步方法的线程竞争。

关于下面的评论 - 只有标记为synchronized的静态方法才会受到类级锁定的影响。如果您希望阻止其他静态方法,则还必须将它们标记为synchronized

为什么会这样?好吧,编译器假设你需要锁定所有你的静态方法,因为它被标记为synchronized,这是相当冒昧的。假设程序员知道必须同步哪些方法以确保线程安全。