JAVA线程锁---Synchronized

一、同步机制关键字synchronized

最常用的同步机制就是synchronized关键字,能够作用于对象、函数、Class。每个对象都只有一个锁,谁能够拿到这个锁谁就有访问权限。
当synchronized作用于函数时,实际上锁的也是对象,锁定的对象就是该函数所在类的对象。而synchronized作用于class时则是锁的当前这个Class对象。故Synchronized 锁存在方法锁、对象锁、类锁的概念。
代码如下:
public class SynchronizedTest {
    /**
     * 同步锁方法-->锁对象
     * 是防止其他线程访问同一个对象中synchronized代码块或函数
     */
    public synchronized void synchronizedMethod(int data) throws InterruptedException {
        //代码
    }
    /**
     * 同步锁块-->锁对象
     * 是防止其他线程访问同一个对象中synchronized代码块或函数
     */
    public void synchronizedThisMethod() throws InterruptedException {
        synchronized (this) {
            //代码
        }
    }
    /**
     * 同步锁class对象-->锁Class对象
     * 是防止多个线程同时访问添加synchronized锁的代码块
     */
    public void synchronizedClassMethod() {
        synchronized (SynchronizedTest.class) {
            //代码
        }
    }
    /**
     * 同步锁静态方法-->锁Class对象
     * 是防止多个线程同时访问添加了synchronized锁的代码块
     */
    public synchronized static void synchronizedStaticMethod() {
        //代码
    }
}

Synchronized 方法锁:

方法锁是指使用Synchronized关键字修饰声明的方法,其实方法锁也就是对象锁的一种写法形式,目的是控制对 类成员变量 的访问。
每个类实例都对应一把锁,所以每个Synchronized方法都必须通过类实例调用,Synchronized 方法一旦执行就会占用该 ,此时若有其他线程A访问该方法,则线程A就会处于阻塞状态直到 方法锁释放,线程A才可获取该锁,从而重新进入可执行状态。
这种机制的好处确保每一个类实例中的Synchronized方法在 同一时刻只能有一个处于可执行状态,从而有效的避免了访问冲突。
l例子:
周杰伦演唱会预售10000张门票,共5个售票窗口,若我们将售票的方法定义同步的,则每个窗口会卖出5张票后才允许其他窗口售票.
代码:
public class SaleDemo {
    //售票总量
    static int saleCount = 10000;

    /**
     * 定以售票窗口同步售票方法
     */
    public synchronized void saleWindows() {
        //每个售票窗口售票数量
        int singleWindowSaleCount = 5;
        for (int index = 0; index < singleWindowSaleCount; index++) {
            saleCount--;
            System.out.println("当前窗口:" + Thread.currentThread().getName() + " | " + "当前剩余:" + saleCount);
        }
    }

    public static void main(String[] arg) {
        //声明一个类的实例
        final SaleDemo saleDemo = new SaleDemo();
        //我们假设开设了5个售票窗口
        for (int index = 0; index < 5; index++) {
            new Thread() {
                @Override
                public void run() {
                    saleDemo.saleWindows();
                }
            }.start();
        }
    }
}

对象锁 有两种表现形式:

  • 锁方法
    public synchronized void saleWindows() {
            //每个售票窗口售票数量
            int singleWindowSaleCount = 5;
            for (int index = 0; index < singleWindowSaleCount; index++) {
                saleCount--;
                System.out.println("当前窗口:" + Thread.currentThread().getName() + " | " + "当前剩余:" + saleCount);
            }
        }
  • 锁代码块
    public void saleWindows() {
            //每个售票窗口售票数量
            int singleWindowSaleCount = 5;
            synchronized (this) {
                for (int index = 0; index < singleWindowSaleCount; index++) {
                    saleCount--;
                    System.out.println("当前窗口:" + Thread.currentThread().getName() + " | " + "当前剩余:" + saleCount);
                }
            }
        }
所以我们上面介绍的 方法锁也是 对象锁的一种.
当一个类中存在Synchronized Method 或 Synchronized Block时,当类实例对象调用Synchronized Method 或 Synchronized Blocks时必须先获取 对象锁,若此对象此时被其他调用者占用,则需要等待对象所被释放 。
这里需要讲解一下的是:JAVA中都包含一个 互斥锁,这个锁由JVM自动获取和释放。
 

Synchronized 类锁

Synchronized类锁同样具有两种表现形式:

  • 静态方法锁
    public static synchronized void saleWindows() {
            //每个售票窗口售票数量
            int singleWindowSaleCount = 5;
            for (int index = 0; index < singleWindowSaleCount; index++) {
                saleCount--;
                System.out.println("当前窗口:" + Thread.currentThread().getName() + " | " + "当前剩余:" + saleCount);
            }
        }
  • 代码块锁
    public void saleWindows() {
            //每个售票窗口售票数量
            int singleWindowSaleCount = 5;
            synchronized (SaleDemo.class) {
                for (int index = 0; index < singleWindowSaleCount; index++) {
                    saleCount--;
                    System.out.println("当前窗口:" + Thread.currentThread().getName() + " | " + "当前剩余:" + saleCount);
                }
            }
        }

    一个Class类不论实例化多少次,其Class中包含的静态变量成员和静态方法在内存中只存在一份。所以一旦一个静态方法加了同步锁,此类中所有实例对象在调用此方法时共用同一把锁,即类锁

    对象锁和类锁的区别

  • 对象锁用来控制类实例方法之间的同步访问
  • 类锁是用来控制静态方法之间的同步访问

猜你喜欢

转载自www.cnblogs.com/blwy-zmh/p/11803640.html