多线程中的类锁和对象锁

时间:2017-06-05 07:57:51

标签: java multithreading synchronization static-methods

我尝试使用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)。
  4. 它的输出是:

    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在上面指出为什么类级别锁定不起作用?

2 个答案:

答案 0 :(得分:2)

  1. 静态方法同步是

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

    public void m2() {
        synchronize (this) {
            ...
        }
    }
    
  3. 现在,如果您要查看this用作监视器的位置以及Resource.class对象用作监视器的位置,那么一切都应该变得清晰。

      

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

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

答案 1 :(得分:0)

关于您的查询:

  

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

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

如果一个线程正在执行resource1.m1()方法,则除非第一个线程完成resource2.m1()的执行,否则其他线程无法执行m1()

由于方法m3()是非同步方法,因此任何线程都可以在不等待并获取锁定的情况下调用此方法。

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

  

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

synchronized methods

制作这些方法synchronized有两个影响:

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

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

  3. static synchronized methods

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