繁体   English   中英

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

[英]Static synchronized methods and non-synchronized static methods confusion

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

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

虽然我仍然有一点混乱,但我们可以很容易地看到xa()也调用actBusy()方法,这是一种静态方法。 方法b()是一个调用非同步静态方法的静态同步方法。 当thread-2获得类级别锁定时,为什么不阻止来自Thread-1的actBusy()调用?

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

为什么不阻止从Thread-1调用actBusy()

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

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

static synchronized方法对类对象有一个锁,而非静态synchronized方法对实例对象有一个锁( this ) - 所以两个方法可以同时调用,一个线程运行1而另一个运行第二个。

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

actBusy()本身不是同步的,但调用方法是。

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

这是因为non-static synchronized上方法锁this本实例而不是class对象。

xa()获取当前实例的锁,即x并且没有其他线程能够输入x方法a() ,直到当前线程释放锁。

线程1 - > xa() //acquires lock and holds it

线程2 ---> xa() //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调用otherStatefulMethod()而线程1持有类锁,那么线程3必须等待,因为该方法也是static-synchornized

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM