synchronized对象锁和类锁.

对象锁概念

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是 异步执行的。

分析:java

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

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锁的是对象。
相关文章
相关标签/搜索