展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > java中各类锁的机制是什么

java中各类锁的机制是什么

前言总结java常见的锁区分各个锁机制以及如何使用使用方法锁名考察线程是否要锁住同步资源乐观锁和悲观锁锁住同步资源后,要不要阻塞不阻塞可以使用自旋锁一个线程多个流程获取同一把锁可重入锁多个线程公用一把锁读写锁(写的共享锁)多个线程竞争要不要排队公平锁与非公平锁1.乐观锁与悲观锁悲观锁:不能同时进行多人,执行的时候先上锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁乐观锁:通过版本号一致与否,即给数据加上版本,同步更新数据以及加上版本号。不会上锁,判断

本文目录

    前言

    总结java常见的锁

    区分各个锁机制以及如何使用

    使用方法锁名
    考察线程是否要锁住同步资源乐观锁和悲观锁
    锁住同步资源后,要不要阻塞不阻塞可以使用自旋锁
    一个线程多个流程获取同一把锁可重入锁
    多个线程公用一把锁读写锁(写的共享锁)
    多个线程竞争要不要排队公平锁与非公平锁

    1. 乐观锁与悲观锁

    悲观锁:不能同时进行多人,执行的时候先上锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁

    乐观锁:通过版本号一致与否,即给数据加上版本,同步更新数据以及加上版本号。不会上锁,判断版本号,可以多人操作,类似生活中的抢票。每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的

    (乐观锁可以使用版本号机制和CAS算法实现)

    java中各类锁的机制是什么

    通过具体案例演示悲观锁和乐观锁

    在redis框架中

    执行multi之前,执行命令watch

    具体格式如下

    watch key1 [key2]

    具体代码格式如下

    127.0.0.1:6379> flushdb
    OK
    127.0.0.1:6379> set add 100
    OK
    127.0.0.1:6379> watch add
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379(TX)> incrby add 20
    QUEUED
    127.0.0.1:6379(TX)> exec
    1) (integer) 120
    127.0.0.1:6379>

    flushdb是清空数据库

    java中各类锁的机制是什么

    但如果在另一个服务器上,输入exec,会显示出错

    因为用的是乐观锁,被修改了之后版本会发生改变

    总的来说:

    悲观锁:单独每个人完成事情的时候,执行上锁解锁。解决并发中的问题,不支持并发操作,只能一个一个操作,效率低

    乐观锁:每执行一件事情,都会比较数据版本号,谁先提交,谁先提交版本号

    2. 公平锁与非公平锁

    公平锁:先来先到

    非公平锁:不是按照顺序,可插队

    • 公平锁:效率相对低

    • 非公平锁:效率高,但是线程容易饿死

    通过这个函数Lock lock = new ReentrantLock(true);。创建一个可重入锁,true 表示公平锁,false 表示非公平锁。默认非公平锁

    通过查看源码

    带有参数的ReentrantLock(true)为公平锁

    ReentrantLock(false)为非公平锁

    主要是调用NonfairSync()与FairSync()

    public ReentrantLock() {
            sync = new NonfairSync();
        }
    
        /**
         * Creates an instance of {@code ReentrantLock} with the
         * given fairness policy.
         *
         * @param fair {@code true} if this lock should use a fair ordering policy
         */
        public ReentrantLock(boolean fair) {
            sync = fair ? new FairSync() : new NonfairSync();
        }

    具体其非公平锁与公平锁的源码

    查看公平锁的源码

    static final class FairSync extends Sync {
       private static final long serialVersionUID = -3000897897090466540L;
    
      /**
      * Acquires only if reentrant or queue is empty.
       */
      final boolean initialTryLock() {
       Thread current = Thread.currentThread();
       int c = getState();
       if (c == 0) {
       if (!hasQueuedThreads() && compareAndSetState(0, 1)) {
         setExclusiveOwnerThread(current);
          return true;
        }
        } else if (getExclusiveOwnerThread() == current) {
          if (++c < 0) // overflow
              throw new Error("Maximum lock count exceeded");
             setState(c);
             return true;
           }
        return false;
    }

    通过代码实例具体操作

    //第一步  创建资源类,定义属性和和操作方法
    class LTicket {
        //票数量
        private int number = 30;
    
        //创建可重入锁
        private final ReentrantLock lock = new ReentrantLock(true);
        //卖票方法
        public void sale() {
            //上锁
            lock.lock();
            try {
                //判断是否有票
                if(number > 0) {
                    System.out.println(Thread.currentThread().getName()+" :卖出"+(number--)+" 剩余:"+number);
                }
            } finally {
                //解锁
                lock.unlock();
            }
        }
    }
    
    public class LSaleTicket {
        //第二步 创建多个线程,调用资源类的操作方法
        //创建三个线程
        public static void main(String[] args) {
    
            LTicket ticket = new LTicket();
    
    new Thread(()-> {
        for (int i = 0; i < 40; i++) {
            ticket.sale();
        }
    },"AA").start();
    
            new Thread(()-> {
                for (int i = 0; i < 40; i++) {
                    ticket.sale();
                }
            },"BB").start();
    
            new Thread(()-> {
                for (int i = 0; i < 40; i++) {
                    ticket.sale();
                }
            },"CC").start();
        }
    }

    结果截图如下

    java中各类锁的机制是什么

    都是A线程执行,而BC线程都没执行到,出现了非公平锁

    具体改变其设置可以通过可重入锁中的一个有参构造方法

    修改代码为private final ReentrantLock lock = new ReentrantLock(true);

    代码截图为

    java中各类锁的机制是什么

    3. 可重入锁

    可重入锁也叫递归锁

    而且有了可重入锁之后,破解第一把之后就可以一直进入到内层结构

    Object o = new Object();
    new Thread(()->{
        synchronized(o) {
            System.out.println(Thread.currentThread().getName()+" 外层");
    
            synchronized (o) {
                System.out.println(Thread.currentThread().getName()+" 中层");
    
                synchronized (o) {
                    System.out.println(Thread.currentThread().getName()+" 内层");
                }
            }
        }
    
    },"t1").start();

    synchronized (o)代表锁住当前{ }内的代码块

    以上都是synchronized锁机制

    下面讲解lock锁机制

    public class SyncLockDemo {
    
        public synchronized void add() {
            add();
        }
    
        public static void main(String[] args) {
            //Lock演示可重入锁
            Lock lock = new ReentrantLock();
            //创建线程
            new Thread(()->{
                try {
                    //上锁
                    lock.lock();
                    System.out.println(Thread.currentThread().getName()+" 外层");
    
                    try {
                        //上锁
                        lock.lock();
                        System.out.println(Thread.currentThread().getName()+" 内层");
                    }finally {
                        //释放锁
                        lock.unlock();
                    }
                }finally {
                    //释放做
                    lock.unlock();
                }
            },"t1").start();
    
            //创建新线程
            new Thread(()->{
                lock.lock();
                System.out.println("aaaa");
                lock.unlock();
            },"aa").start();
            }
     }

    在同一把锁中的嵌套锁,内部嵌套锁没解锁还是可以输出,但是如果跳出该线程,执行另外一个线程就会造成死锁

    要把握上锁与解锁的概念,都要写上

    java中各类锁的机制是什么

    4. 读写锁(共享锁与独占锁)

    读锁是共享锁,写锁是独占锁

    • 共享锁的一种具体实现

    • 读写锁管理一组锁,一个是只读的锁,一个是写锁。

    读写锁:一个资源可以被多个读线程访问,也可以被一个写线程访问,但不能同时存在读写线程,读写互斥,读读共享(写锁独占,读锁共享,写锁优先级高于读锁)

    读写锁ReentrantReadWriteLock

    读锁为ReentrantReadWriteLock.ReadLock,readLock()方法

    写锁为ReentrantReadWriteLock.WriteLock,writeLock()方法

    创建读写锁对象private ReadWriteLock rwLock = new ReentrantReadWriteLock();

    写锁 加锁 rwLock.writeLock().lock();,解锁为rwLock.writeLock().unlock();

    读锁 加锁rwLock.readLock().lock();,解锁为rwLock.readLock().unlock();

    案例分析:

    模拟多线程在map中取数据和读数据

    完整代码如下

    //资源类
    class MyCache {
        //创建map集合
        private volatile Map map = new HashMap<>();
    
        //创建读写锁对象
        private ReadWriteLock rwLock = new ReentrantReadWriteLock();
    
        //放数据
        public void put(String key,Object value) {
            //添加写锁
            rwLock.writeLock().lock();
    
            try {
                System.out.println(Thread.currentThread().getName()+" 正在写操作"+key);
                //暂停一会
                TimeUnit.MICROSECONDS.sleep(300);
                //放数据
                map.put(key,value);
                System.out.println(Thread.currentThread().getName()+" 写完了"+key);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //释放写锁
                rwLock.writeLock().unlock();
            }
        }
    
        //取数据
        public Object get(String key) {
            //添加读锁
            rwLock.readLock().lock();
            Object result = null;
            try {
                System.out.println(Thread.currentThread().getName()+" 正在读取操作"+key);
                //暂停一会
                TimeUnit.MICROSECONDS.sleep(300);
                result = map.get(key);
                System.out.println(Thread.currentThread().getName()+" 取完了"+key);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //释放读锁
                rwLock.readLock().unlock();
            }
            return result;
        }
    }
    
    public class ReadWriteLockDemo {
        public static void main(String[] args) throws InterruptedException {
            MyCache myCache = new MyCache();
            //创建线程放数据
            for (int i = 1; i <=5; i++) {
                final int num = i;
                new Thread(()->{
                    myCache.put(num+"",num+"");
                },String.valueOf(i)).start();
            }
    
            TimeUnit.MICROSECONDS.sleep(300);
    
            //创建线程取数据
            for (int i = 1; i <=5; i++) {
                final int num = i;
                new Thread(()->{
                    myCache.get(num+"");
                },String.valueOf(i)).start();
            }
        }
    }

    5. 互斥锁

    互斥锁是独占锁的一种常规实现,是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性

    pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//创建互斥锁并初始化
    
    pthread_mutex_lock(&mutex);//对线程上锁,此时其他线程阻塞等待该线程释放锁
    
    //要执行的代码段
    
    pthread_mutex_unlock(&mutex);//执行完后释放锁

    6. 自旋锁

    查看百度百科的解释,具体如下 :

    它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名

    通俗的来说就是一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务。

    其特点:

    1. 持有锁时间等待过长,消耗CPU

    2. 无法满足等待时间最长的线程优先获取锁。不公平的锁就会存在“线程饥饿”问题

    3. 自旋锁不会使线程状态发生切换,处于用户态(不会到内核态进行线程的状态转换),一直都是活跃,不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快。

    其模拟算法如下

    do{
    	b=1;
    	while(b){
    		lock(bus);
    		b = test_and_set(&lock);
    		unlock(bus);
    	}
    	//临界区
    	//lock = 0;
    	//其余部分
    }while(1)

    7. 无锁 / 偏向锁 / 轻量级锁 / 重量级锁

    • 无锁:没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功

    • 偏向锁:是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁,降低获取锁的代价

    • 轻量级锁:锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能

    • 重量级锁:线程并发加剧,线程的自旋超过了一定次数,或者一个线程持有锁,一个线程在自旋,还有线程要访问

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    AirServer Windows版
    AirServer Windows版

    AirServer Windows版可把电脑变成AirPlay、Google Cast和Miracast无线投屏接收端,适合会议演示、课堂教学及家庭大屏分享。发送设备通常无需另装客户端,并可同时接收和智能排列多个镜像会话。

    AlwaysUp Windows版
    AlwaysUp Windows版

    AlwaysUp是一款面向Windows的系统服务注册与程序托管工具,可让普通应用、脚本及批处理在无人登录时随系统启动,并通过状态检测、异常重启、资源监控和邮件通知保障关键任务持续运行。