zoukankan      html  css  js  c++  java
  • 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中包含的静态变量成员和静态方法在内存中只存在一份。所以一旦一个静态方法加了同步锁,此类中所有实例对象在调用此方法时共用同一把锁,即类锁

      对象锁和类锁的区别

    • 对象锁用来控制类实例方法之间的同步访问
    • 类锁是用来控制静态方法之间的同步访问
  • 相关阅读:
    ES6-11学习笔记--正则表达式的扩展
    ES6-11学习笔记--字符串的扩展
    ES6-11学习笔记--Map
    ES6-11学习笔记--Set
    ES6-11学习笔记--Symbol
    final
    MySQL
    爬虫1
    laravel
    HTML学习
  • 原文地址:https://www.cnblogs.com/blwy-zmh/p/11803640.html
Copyright © 2011-2022 走看看