关于Java:第一个线程锁定该类时第二个线程会发生什么

what happen to second thread when the first thread lock the class

好吧,说我有一个Java Math类,该类具有线程安全的实现。线程A现在正在执行SetValue(1),这将导致Math类被锁定。如果线程B尝试同时使用GetValue()进行访问,将会发生什么情况?它会一直等到锁定释放或方法请求直接终止而没有警告或异常吗?

1
2
3
4
5
6
7
8
9
10
11
public class Math {
      private static int value = 0;

      public synchronized static void setValue(int value) {
           Math.value = value;
      }

      public synchronized static int getValue() {
           return value;
      }
}


是,第二个线程将等待,直到锁再次可用。如果该锁永不可用,则将出现活动问题,第二个线程将挂起。

在JLS 17.1中有更详细的描述:

A synchronized method automatically performs a lock action when it is invoked; its body is not executed until the lock action has successfully completed. [...] If execution of the method's body is ever completed, either normally or abruptly, an unlock action is automatically performed on that same monitor.

另请注意:

The Java programming language neither prevents nor requires detection of deadlock conditions. Programs where threads hold (directly or indirectly) locks on multiple objects should use conventional techniques for deadlock avoidance, creating higher-level locking primitives that do not deadlock, if necessary.


一个小插图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Math {

 private static int value = 0;

 public synchronized static void SetValue(int _value) throws InterruptedException {

  Thread.sleep(1000L);
  value = _value;
 }

 public synchronized static int GetValue()  {

  return value;
 }

 public static void main(String[] args) {

  new Thread(new Runnable() {

   @Override
   public void run() {

    try {
     SetValue(-100);
    } catch (InterruptedException e) {
     // ignore
    }
   }
  }).start();

  new Thread(new Runnable() {

   @Override
   public void run() {

    System.out.println("GetValue() =" + GetValue());
   }
  }).start();
 }
}

输出为:

1
GetValue() = -100

这意味着第二个线程将在睡眠一秒钟并将value设置为100之后等待第一个线程唤醒。


Thread被添加到等待队列中,并保持在那里,直到Thread A执行SetValue方法为止,并且不释放锁。

Thread A释放锁定后,会立即通知Thread B,此后它可以继续。

还请注意,当Thread A进入SetValue方法时,它将获得该类所有同步方法的锁定。因此,在Thread A完成执行SetValue方法并逐渐释放锁定之前,Thread B无法执行任何synchronized method

还有另一件事,不能保证一旦释放锁,Thread B将立即开始执行GetValue方法。这完全取决于CPU,何时将资源分配给线程B。

P.S:-请遵循您代码中的Java命名约定。您的方法名称应以lowercase字母开头。因此,您的方法应为GetValueSetValue


它将在必要时永远等待第一个线程释放锁。