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

      对象锁和类锁的区别

    • 对象锁用来控制类实例方法之间的同步访问
    • 类锁是用来控制静态方法之间的同步访问
  • 相关阅读:
    将单向链表按某值划分为左边小、中间相等、右边大的形式
    数组中的数字按某值划分为左边小、中间相等、右边大的形式
    Kendo UI for jQuery管理数据有妙招!轻松将数据存储为JSON
    DevExpress Xamarin.Forms v21.1
    界面控件Telerik UI for WinForm初级教程
    WPF应用程序的主题颜色如何修改?DevExpress调色板工具很好用
    DevExpress WinForm模板库可快速创建Windows样式的应用程序界面
    Kendo UI for jQuery数据管理使用教程:Spreadsheet
    开发框架DevExtreme入门级教程
    跨平台.NET应用程序界面开发新亮点
  • 原文地址:https://www.cnblogs.com/blwy-zmh/p/11803640.html
Copyright © 2020-2023  润新知