关于java:synchronized对象锁和类锁

6次阅读

共计 3665 个字符,预计需要花费 10 分钟才能阅读完成。

对象锁概念

Java 的所有对象都含有 1 个互斥锁,这个锁由 JVM 主动获取和开释。线程进入 synchronized 办法的时候获取该对象的锁,当然如果曾经有线程获取了这个对象的锁,那么以后线程会期待,synchronized 办法失常返回或者抛异样而终止,JVM 会主动开释对象锁。这里也体现了用 synchronized 来加锁的一个益处,办法抛异样的时候,锁依然能够由 JVM 来主动开释。

    // 对象锁:模式 1(办法锁)
    public synchronized void Method1() {System.out.println("我是对象锁也是办法锁");
        try {Thread.sleep(500);
        } catch (InterruptedException e) {e.printStackTrace();
        }

    }

    // 对象锁:模式 2(代码块模式)public void Method2() {synchronized (this) {System.out.println("我是对象锁");
            try {Thread.sleep(500);
            } catch (InterruptedException e) {e.printStackTrace();
            }
        }

    }

类锁的概念

因为一个 class 不管被实例化多少次,其中的静态方法和动态变量在内存中都只有一份。所以,一旦一个动态的办法被申明为 synchronized。此类所有的实例化对象在调用此办法,共用同一把锁,咱们称之为类锁。

public synchronized static void Method3() {System.out.println("我是类锁");
        try {Thread.sleep(500);
        } catch (InterruptedException e) {e.printStackTrace();
        }
}

代码演示类锁和对象锁

上面这段代码是两个类锁和一个对象锁,拿到锁后,睡 1 秒钟。

    // 类锁 A
    public synchronized static void classLockA() {System.out.println("name =" + Thread.currentThread().getName() + ", begain");
        try {Thread.sleep(1000);
        } catch (InterruptedException e) {e.printStackTrace();
        }
        System.out.println("name =" + Thread.currentThread().getName() + ", end");
    }

    // 类锁 B
    public synchronized static void classLockB() {System.out.println("name =" + Thread.currentThread().getName() + ", begain");
        try {Thread.sleep(1000);
        } catch (InterruptedException e) {e.printStackTrace();
        }
        System.out.println("name =" + Thread.currentThread().getName() + ", end");
    }

    // 对象锁
    public synchronized void objectLock() {System.out.println("name =" + Thread.currentThread().getName() + ", begain");
        try {Thread.sleep(1000);
        } catch (InterruptedException e) {e.printStackTrace();
        }
        System.out.println("name =" + Thread.currentThread().getName() + ", end");

    }

创立三个线程类:别离调用一个资源中的三个办法

class ThreadA extends Thread {
    
    private Test02 test02;
    
    public ThreadA(Test02 tk) {test02 = tk;}
    
    // 调用类锁
    public void run() {test02.classLockA();
    }
}

class ThreadB extends Thread {
    
    private Test02 test02;
    
    public ThreadB(Test02 tk) {test02 = tk;}
    
    // 调用类锁
    public void run() {test02.classLockB();
    }
}

class ThreadC extends Thread {
    
    private Test02 test02;
    
    public ThreadC(Test02 tk) {test02 = tk;}
    
    // 调用对象锁
    public void run() {test02.objectLock();
    }
}

main 办法:起了三个线程,独特拜访一个 Test02 对象

public static void main(String[] args){Test02 test02 = new Test02();
        ThreadA ta = new ThreadA(test02);
        ThreadB tb = new ThreadB(test02);
        ThreadC tc = new ThreadC(test02);

        ta.setName("A");
        tb.setName("B");
        tc.setName("C");

        ta.start();
        tb.start();
        tc.start();}

执行的后果:

name = A, begain
name = C, begain
name = A, end
name = B, begain
name = C, end
name = B, end

能够看出因为 classLockA 和 classLockB 都是类锁,即同一个锁,所以 A 和 B 是按程序执行,即同步的。而 C 是对象锁,和 A / B 不是同一种锁,所以 C 和 A、B 是 异步执行的。

剖析:

对象锁要想放弃同步执行,那么锁住的必须是同一个对象,举个例子:

Test02 类不变,重起两个线程类:均对对象锁进行了调用

class ThreadA extends Thread {
    
    private Test02 test02;
    
    public ThreadA(Test02 tk) {test02 = tk;}
    
    // 调用类锁
    public void run() {test02.objectLock();
    }
}

class ThreadB extends Thread {
    
    private Test02 test02;
    
    public ThreadB(Test02 tk) {test02 = tk;}
    
    // 调用类锁
    public void run() {test02.objectLock();
    }
}

main 办法:创立两个不同的资源对象,启动两个线程,别离对加锁的办法进行调用

public static void main(String[] args){Test02 test02 = new Test02();
        Test02 test03 = new Test02();
        ThreadA ta = new ThreadA(test02);
        ThreadB tb = new ThreadB(test03);

        ta.setName("A");
        tb.setName("B");

        ta.start();
        tb.start();}

后果可见,是异步执行的,没有达到同步的作用。

name = A, begain
name = B, begain
name = A, end
name = B, end

改良:只需对类锁进行调用,代码如下:

class ThreadA extends Thread {
    
    private Test02 test02;
    
    public ThreadA(Test02 tk) {test02 = tk;}
    
    // 调用类锁
    public void run() {test02.classLockA();
    }
}

class ThreadB extends Thread {
    
    private Test02 test02;
    
    public ThreadB(Test02 tk) {test02 = tk;}
    
    // 调用类锁
    public void run() {test02.classLockA();
    }
}

main 办法:同样是创立了多个对象

public static void main(String[] args){Test02 test02 = new Test02();
        Test02 test03 = new Test02();
        ThreadA ta = new ThreadA(test02);
        ThreadB tb = new ThreadB(test03);

        ta.setName("A");
        tb.setName("B");

        ta.start();
        tb.start();}

后果达到了同步的成果!

name = A, begain
name = A, end
name = B, begain
name = B, end

总结:

  1. 如果多线程同时拜访同一类的 类锁(synchronized 润饰的静态方法)以及对象锁(synchronized 润饰的非静态方法)这两个办法执行是异步的,起因:类锁和对象锁是 2 中不同的锁。
  2. 类锁对该类的所有对象都能起作用,而对象锁不能。
  3. synchronized 锁的是对象。
正文完
 0