• Java中的锁-悲观锁、乐观锁,公平锁、非公平锁,互斥锁、读写锁


     

     

    总览图

    这里写图片描述

    如果文中内容有错误,欢迎指出,谢谢。

    悲观锁、乐观锁

    悲观锁、乐观锁使用场景是针对数据库操作来说的,是一种锁机制。

    悲观锁(Pessimistic Lock):顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

    乐观锁(Optimistic Lock):顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制,即对数据做版本控制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。

    公平锁、非公平锁

    公平锁(Fair):加锁前检查是否有排队等待的线程,优先排队等待的线程,先来先得。

    非公平锁(Nonfair):加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待。

    ReentrantLock锁内部提供了公平锁与分公平锁内部类之分,默认是非公平锁,如:

       public ReentrantLock() {
            sync = new NonfairSync();
        }
        public ReentrantLock(boolean fair) {
            sync = fair ? new FairSync() : new NonfairSync();
        }

    互斥锁、读写锁

    互斥锁:指的是一次最多只能有一个线程持有的锁。在jdk1.5之前, 我们通常使用synchronized机制控制多个线程对共享资源的访问。 而现在, Lock提供了比synchronized机制更广泛的锁定操作, Lock和synchronized机制的主要区别: 
    synchronized机制提供了对与每个对象相关的隐式监视器锁的访问,并强制所有锁获取和释放均要出现在一个块结构中,当获取了多个锁时, 它们必须以相反的顺序释放。synchronized机制对锁的释放是隐式的,只要线程运行的代码超出了synchronized语句块范围,锁就会被释放。而Lock机制必须显式的调用Lock对象的unlock()方法才能释放锁,这为获取锁和释放锁不出现在同一个块结构中,以及以更自由的顺序释放锁提供了可能。

    读写锁:ReadWriteLock接口及其实现类ReentrantReadWriteLock,默认情况下也是非公平锁。

    ReentrantReadWriteLock中定义了2个内部类,ReentrantReadWriteLock.ReadLock和ReentrantReadWriteLock.WriteLock,分别用来代表读取锁和写入锁,ReentrantReadWriteLock对象提供了readLock()和writeLock()方法,用于获取读取锁和写入锁。

    java.util.concurrent.locks.ReadWriteLock接口允许一次读取多个线程,但一次只能写入一个线程:

    • 读锁 - 如果没有线程锁定ReadWriteLock进行写入,则多线程可以访问读锁。

    • 写锁 - 如果没有线程正在读或写,那么一个线程可以访问写锁。

    其中:

    • 读取锁允许多个reader线程同时持有,而写入锁最多只能有一个writer线程持有。
    • 读写锁的使用场合是:读取数据的频率远大于修改共享数据的频率。在上述场合下使用读写锁控制共享资源的访问,可以提高并发性能。
    • 如果一个线程已经持有了写入锁,则可以再持有读锁。相反,如果一个线程已经持有了读取锁,则在释放该读取锁之前,不能再持有写入锁。
    • 可以调用写入锁的newCondition()方法获取与该写入锁绑定的Condition对象,此时与普通的互斥锁并没有什么区别,但是调用读取锁的newCondition()方法将抛出异常。

    参考

    http://www.cnblogs.com/hane/p/7344572.html

    http://www.cnblogs.com/jalja/p/5895051.html

    http://www.cnblogs.com/aspirant/p/6747115.html

  • 相关阅读:
    【Linux】- Systemd 命令篇
    【Linux】- 守护进程的启动方法
    【Linux】- CentOS安装docker及docker-compose
    【Python】- scrapy 爬取图片保存到本地、且返回保存路径
    解决百度ueditor支持iframe框架页面的视频播放问题
    php CURL 请求头和响应头获取
    phpcms pc标签 start不生效的原因
    单点登录的实现
    Linux下删除相互依赖的包
    如何通过js关闭微信浏览器页面
  • 原文地址:https://www.cnblogs.com/JonaLin/p/11571784.html
Copyright © 2020-2023  润新知