Java 中对象锁和类锁的区别?

一  对象锁和类锁的关系 

/*
 * 
 对象锁和【类锁】 全局锁的关系?
        对象锁是用于对象实例方法,或者一个对象实例上的   this
        类锁是用于类的静态方法或者一个类的class对象上的。 Ag.class
        
        我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,
        所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。
 */

对象锁,  不同对象。

public class SynchrDemo {
    public static void main(String[] args) {
        
        Thread1 thread1 = new Thread1();
        Thread1 thread2 = new Thread1();
        
        thread1.start();
        thread2.start();

    }
}

class Ag{
    public void show(){
        // this 是当前对象的实例,由于新建两个对象,不是同一对象。所以这里是锁不住的。   代码快的方式,比修饰在方法上更细化控制。
        synchronized (this) {
            for (int i = 0; i < 4; i++) {
                System.out.println(Thread.currentThread().getName() + " i=" + i);
            }
        }
    }

}

class Thread1 extends Thread{    
    @Override
    public void run() {
        //这里是新建对象  主方法中new了两个thread,就是new了两个Ag对象
        Ag ag = new Ag();
        ag.show();
        
    }    
}

关键字修饰方法

public class SynchrDemo {
    public static void main(String[] args) {
        
        Thread1 thread1 = new Thread1();
        Thread1 thread2 = new Thread1();
        
        thread1.start();
        thread2.start();

    }
}

class Ag{
    // 这次修饰的是方法,范围比代码块要大,意味着在这个区域内,锁生效的时候,都是在阻塞,其他线程的等待时间就会增加。
    // 这次实验的非同一对象,所以这里的锁是不起作用的。
    public synchronized void show(){
            for (int i = 0; i < 4; i++) {
                System.out.println(Thread.currentThread().getName() + " i=" + i);
            }
    }

}

class Thread1 extends Thread{    
    @Override
    public void run() {
        //这里是新建对象  主方法中new了两个thread,就是new了两个Ag对象
        Ag ag = new Ag();
        ag.show();
        
    }    
}

二  对象锁  同一对象

package com.aaa.threaddemo;
/*
 * 一 Java中的关键字  synchronized  是啥?
 *         synchronized是Java提供的一个并发控制的关键字。
 * 
 *         用法:同步方法 和 同步代码块。
 *              可以修饰方法 也可以  修饰代码块。
 *         
 *         作用: 被synchronized修饰的代码块及方法,在同一时间,只能被单个线程访问。【保证线程安全】

    1 修饰方法和代码块有什么不同?
         二者的结果是一样的
         
         修饰方法时,作用域是整个方法,控制的范围大。
     
         synchronized 代码块 可控制具体的作用域,更精准控制提高效率。
         减少阻塞带来的时间问题。

    2 同步锁的给谁用的?
        同步锁基于对象,只要锁的来源一致,即可达到同步的作用。
        所以,但对象不一样,则不能达到同步效果。

    3 synchronized修饰方法,代码块,锁未释放,此时,其他线程调用同一对象的其他被synchronized修饰的方法,代码块,会如何?
        当线程 A 调用某对象的synchronized 方法 或者 synchronized 代码块时,若同步锁未释放,
        其他线程调用同一对象的其他 synchronized 方法 或者 synchronized 代码块时将被阻塞,直至线程 A 释放该对象的同步锁。(注意:重点是其他)

    4 调用非synchronized方法 ,代码快呢?
        当线程 A 调用某对象的synchronized 方法 或者 synchronized 代码块时,无论同步锁是否释放,
        其他线程调用同一对象的其他 非 synchronized 方法 或者 非 synchronized 代码块时可立即调用。

    5 全局锁如何实现?
        全局锁: 锁住整个 Class,而非某个对象或实例。1-4都是实例锁
        实现: 静态 synchronized 方法
        
        static 声明的方法为全局方法,与对象实例化无关,
        所以 static synchronized 方法为全局同步方法,与对象实例化无关。

    6 synchronized 具体 Class 的代码块?
        synchronized (Ag.class) 获得的同步锁是全局的,
        static synchronized 获得的同步锁也是全局的,同一个锁,所以达到同步效果。

    7 对象锁和【类锁】 全局锁的关系?
        对象锁是用于对象实例方法,或者一个对象实例上的   this
        类锁是用于类的静态方法或者一个类的class对象上的。 Ag.class
        
        我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,
        所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。




 * 
 * 
 */

/*
 * 
 对象锁和【类锁】 全局锁的关系?
        对象锁是用于对象实例方法,或者一个对象实例上的   this
        类锁是用于类的静态方法或者一个类的class对象上的。 Ag.class
        
        我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,
        所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。
 */


public class SynchrDemo {
    public static void main(String[] args) {
        
        // 改造后,可以确保是同一对象  验证  synchronized  是否生效
        Ag ag = new Ag();
        
        Thread1 thread1 = new Thread1(ag);
        Thread1 thread2 = new Thread1(ag);
        
        thread1.start();
        thread2.start();

    }
}

class Ag{
    // 这次修饰的是方法,范围比代码块要大,意味着在这个区域内,锁生效的时候,都是在阻塞,其他线程的等待时间就会增加。
    // 这次实验的同一对象,所以这里的锁是起作用的。
    public synchronized void show(){
            for (int i = 0; i < 4; i++) {
                System.out.println(Thread.currentThread().getName() + " i=" + i);
            }
    }

}

/*
 *   改造一些 对象的生成,确保在Thread1 中获得的是同一对象
 */
class Thread1 extends Thread{    
    
    private Ag mag;
    
    public  Thread1(Ag ag) {
        mag = ag;
    }
    
    @Override
    public void run() {
        mag.show();
        
    }    
}

验证代码快的方式?

public class SynchrDemo {
    public static void main(String[] args) {
        
        // 改造后,可以确保是同一对象  验证  synchronized  是否生效
        Ag ag = new Ag();
        
        Thread1 thread1 = new Thread1(ag);
        Thread1 thread2 = new Thread1(ag);
        
        thread1.start();
        thread2.start();

    }
}

class Ag{
    // 这次修饰的是方法,范围比代码块要大,意味着在这个区域内,锁生效的时候,都是在阻塞,其他线程的等待时间就会增加。
    // 这次实验的同一对象,所以这里的锁是起作用的。
    public  void show(){
        synchronized (this) {
            for (int i = 0; i < 4; i++) {
                System.out.println(Thread.currentThread().getName() + " i=" + i);
            }
            
            // this 就是当前的对象,我们现在获得就是同一对象
            System.out.println(this);
        }
    }

}

/*
 *   改造一些 对象的生成,确保在Thread1 中获得的是同一对象
 */
class Thread1 extends Thread{    
    
    private Ag mag;
    
    public  Thread1(Ag ag) {
        mag = ag;
    }
    
    @Override
    public void run() {
        mag.show();
        
    }    
}

三   类锁?  非同一对象

/*
 * 
 * 类锁,全局锁如何实现?
        全局锁: 锁住整个 Class,而非某个对象或实例
        
        实现:   
        1    在静态方法上用 synchronized 关键字修饰
        2    在代码块上使用 类名.class
            
        
        static 声明的方法为全局方法,与对象实例化无关,
        所以 static synchronized 方法为全局同步方法,与对象实例化无关。
 */

public class SynchrDemo {
    public static void main(String[] args) {
        
        //非同一对象
        Thread2 thread1 = new Thread2();
        Thread2 thread2 = new Thread2();
        
        thread1.start();
        thread2.start();

    }
}

class Ag{
    public  void show(){
        // 使用 synchronized()  方法,将锁控制在代码快上。
        synchronized (Ag.class) {
            for (int i = 0; i < 4; i++) {
                System.out.println(Thread.currentThread().getName() + " i=" + i);
            }
            
            // this 就是当前的对象,我们现在获得就是非同一对象
            System.out.println(this);
        }
    }

}

class Thread2 extends Thread{
    
    @Override
    public void run() {
        Ag ag = new Ag();
        ag.show();
        
    }    
}

测试   关键字修饰 static 方法  

public class SynchrDemo {
    public static void main(String[] args) {
        
        //非同一对象
        Thread2 thread1 = new Thread2();
        Thread2 thread2 = new Thread2();
        
        thread1.start();
        thread2.start();

    }
}

class Ag{
    // 静态的方法  被synchronized 修饰后, 锁住的是 类。
    public static synchronized  void show(){
            for (int i = 0; i < 4; i++) {
                System.out.println(Thread.currentThread().getName() + " i=" + i);
            }            
    }

}

class Thread2 extends Thread{
    
    @Override
    public void run() {
        Ag ag = new Ag();
        ag.show();
        
    }    
}

原文地址:https://www.cnblogs.com/ZXF6/p/14102874.html