【问题标题】:Class Lock And Object Lock In Multithreading多线程中的类锁和对象锁
【发布时间】:2017-11-05 22:51:06
【问题描述】:

我用static 函数和非静态函数作为synchronized 尝试了一个面试问题,其中一个函数是非同步的。如下代码:

public class Resource {

public static synchronized void m1() throws InterruptedException {
    System.out.println("Entering m1 method");
    Thread.sleep(10000);
    System.out.println("Leaving m1 method");
    System.out.println();
}

public synchronized void m2() throws InterruptedException {
    System.out.println("Entering m2 method");
    Thread.sleep(2000);
    System.out.println("Leaving m2 method");
    System.out.println();
}

public void m3() throws InterruptedException {
    System.out.println("Entering m3 method");
    Thread.sleep(2000);
    System.out.println("Leaving m3 method");
    System.out.println();
}

public synchronized void m4() throws InterruptedException {
    System.out.println("Entering m4 method");
    Thread.sleep(2000);
    System.out.println("Leaving m4 method");
    System.out.println();
}

}

public class ThreadDemo {

public static void main(String[] args) {

    final Resource resource = new Resource();

    Thread t1 = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                resource.m1();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    });

    Thread t2 = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                resource.m2();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    });

    Thread t3 = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                resource.m3();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    });

    Thread t4 = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                resource.m4();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    });

    t1.start();
    t2.start();
    t3.start();
    t4.start();
}

}

这里创建了四个线程。

  1. T1 正在调用静态同步(m1)
  2. T2、T4 正在调用 synchronized(m2, m4) 和
  3. T3 正在调用非同步 (m3)。

它的输出是:

Entering m1 method
Entering m3 method
Entering m2 method
Leaving m3 method

Leaving m2 method

Entering m4 method
Leaving m4 method

Leaving m1 method

我的问题是:

1) 静态同步方法使类级锁定。这里的类级别锁定是什么意思?如果一个线程已经获得锁并且类级别的锁被占用,那么为什么线程 T2 和 T3 开始执行?

2) T4 正在等待完成 T2。虽然同步应用在两种不同的方法上,但为什么 T4 还要等待呢?如果对象级锁定在 T2、T4 中起作用,那么在上述几点中,为什么类级锁定不起作用?

【问题讨论】:

    标签: java multithreading synchronization static-methods


    【解决方案1】:
    1. 静态方法同步等价于

      public static void m1() {
          synchronize (Resource.class) {
          ...
          }
      }
      
    2. 非静态方法同步等价于

      public void m2() {
          synchronize (this) {
              ...
          }
      }
      

    现在,如果您查看this 用作监视器的位置以及Resource.class 对象用作监视器的位置,那么一切都应该清楚了。

    Java 中的同步块在某个对象上同步。在同一个对象上同步的所有同步块只能同时在其中执行一个线程。所有其他试图进入同步块的线程都被阻塞,直到同步块内的线程退出该块。

    在您的情况下,有两个对象。因此,此规则适用于每个对象,但不能同时适用于两者。

    【讨论】:

      【解决方案2】:

      关于您的查询:

      1) 静态同步方法使类级锁定。这里的类级别锁定是什么意思?如果一个线程已经拿了锁,并且类级别的锁被占用了,那为什么线程 T2 和 T3 开始执行呢?

      static synchronized 方法的情况下,只有一个线程在多个类实例中获取这些方法的锁。如果您有两个不同的实例:resource1resource2 用于 Resource 类,则只有一个线程会成功锁定 m1()

      如果resource1.m1()方法正在被一个线程执行,其他线程不能执行resource2.m1(),除非第一个线程完成m1()的执行。

      由于方法m3()是非同步方法,任何线程都可以调用该方法而无需等待和获取锁。

      由于m2()m4() 都是同步的,因此只有一个线程会成功锁定同一对象(在您的示例中为resource)。其他线程必须等到第一个线程完成synchrnozied方法的执行并释放对象级锁。

      2) T4 正在等待完成 T2。虽然同步应用于两种不同的方法,但为什么 T4 必须等待?如果对象级锁在 T2 中工作,T4 那么在上述点为什么类级锁定不起作用?

      synchronized methods:

      使这些方法synchronized 有两个效果:

      1. 首先,不可能对同一对象进行两次synchronized 方法的调用交错。当一个线程正在为一个对象执行synchronized 方法时,所有其他为同一对象调用同步方法的线程都会阻塞(暂停执行),直到第一个线程处理完该对象。

      2. 其次,当一个同步方法退出时,它会自动与任何后续对同一对象的同步方法调用建立起之前的关系。这保证了对象状态的更改对所有线程都是可见的。

      static synchronized methods:

      线程获取与类关联的Class 对象的内在锁。因此,对类的static 字段的访问是由一个锁控制的,该锁不同于该类的任何实例的锁。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-31
        • 1970-01-01
        • 2018-06-20
        相关资源
        最近更新 更多