在java中有哪些锁?该如何进行分类呢?

=========================================

原文链接:多线程(五) java的线程锁 转载请注明出处!

=========================================


一、在java中有哪些锁?该如何进行分类呢?

1、共享锁/排它锁 

    共享锁和排他锁是从同一时刻是否允许多个线程持有该锁的角度来划分。
              共享锁允许同一时刻多个线程进入持有锁,访问临界区资源。而排他锁就是通常意义上的锁,同一时刻只允许一个线程访问临界资源。对于共享锁,主要是指对数据库读操作中的读锁,在读写资源的时候如果没有线程持有写锁和请求写锁,则此时允许多个线程持有读锁。
              在这里理解共享锁的时候,不是任意时刻都允许多线程持有共享锁的,而是在某些特殊情况下才允许多线程持有共享锁,在某些情况下不允许多个线程持有共享锁,否则,如果没有前提条件任意时刻都允许线程任意持有共享锁,则共享锁的存在无意义的。例如读写锁中的读锁,只有当没有写锁和写锁请求的时候,就可以允许多个线程同时持有读锁。这里的前提条件就是“没有写锁和写锁请求”,而不是任意时刻都允许多线程持有共享读锁。
  2、悲观锁/乐观锁  
            主要用于数据库数据的操作中,而对于线程锁中较为少见。
            悲观锁和乐观锁是一种加锁思想。对于乐观锁,在进行数据读取的时候不会加锁,而在进行写入操作的时候会判断一下数据是否被其它线程修改过,如果修改则更新数据,如果没有则继续进行数据写入操作。乐观锁不是系统中自带的锁,而是一种数据读取写入思想。应用场景例如:在向数据库中插入数据的时候,先从数据库中读取记录修改版本标识字段,如果该字段没有发生变化(没有其他线程对数据进行写操作)则执行写入操作,如果发生变化则重新计算数据。
             对于悲观锁,无论是进行读操作还是进行写操作都会进行加锁操作。对于悲观锁,如果并发量较大则比较耗费资源,当然保证了数据的安全性。

 3、可重入锁/不可重入
                这两个概念是从同一个线程在已经持有锁的前提下能否再次持有锁的角度来区分的。
                对于可重入锁,如果该线程已经获取到锁且未释放的情况下允许再次获取该锁访问临界区资源。此种情况主要是用在递归调用的情况下和不同的临界区使用相同的锁的情况下。
                对于不可重入锁,则不允许同一线程在持有锁的情况下再次获取该锁并访问临界区资源。对于不可重入锁,使用的时候需要小心以免造成死锁。

 4、公平锁/非公平锁
                这两个概念主要使用线程获取锁的顺序角度来区分的。
                对于公平锁,所有等待的线程按照按照请求锁的先后循序分别依次获取锁。
                对于非公平锁,等待线程的线程获取锁的顺序和请求的先后不是对应关系。有可能是随机的获取锁,也有可能按照其他策略获取锁,总之不是按照FIFO的顺序获取锁。
                在使用ReentrantLock的时候可以通过构造方法主动选择是实现公平锁还是非公平锁。

5、自旋锁/非自旋锁
                这两种概念是从线程等待的处理机制来区分的。
                自旋锁在进行锁请求等待的时候不进行wait挂起,不释放CPU资源,执行while空循环。直至获取锁访问临界区资源。适用于等待锁时间较短的情景,如果等待时间较长,则会耗费大量的CPU资源。而如果等待时间较短则可以节约大量的线程切换资源。
                非自旋锁在进行锁等待的时候会释放CPU资源,可以通多sleep wait 或者CPU中断切换上下文,切换该线程。在线程等待时间较长的情况下可以选择此种实现机制。
        除此之外还有一种介于两者之间的锁机制——自适应自旋锁。当线程进行等待的时候先进性自旋等待,在自旋一定时间(次数)之后如果依旧没有持有锁则挂起等待。在jvm中synchronized锁已经使用该机制进行处理锁等待的情况。
在工作中可以根据不同的情况选取合适的锁进行使用。无论使用哪种锁,其目的都是保证程序能够按照要求顺利执行,避免数据混乱情况的发生。

二、常用锁的使用方法


        1、synchronized锁:

    对于synchronized锁首先需要明白加锁的底层原理。每一个对象实例在对象头中都会有monitor record列表记录持有该锁的线程,底层通多对该列表的查询来判断是否已经有线程在访问临界区资源。JVM内部细节之一:synchronized关键字及实现细节(轻量级锁Lightweight Locking)

    在使用synchronized的时候必须弄清楚谁是“钥匙”,属于全局变量还是线程内局部变量,每个加锁的临界区是使用的哪个“钥匙”对象。必须理清楚加锁线程和“钥匙”对象的关系!!!!

    synchronized只可以对方法和方法中的代码块进行加锁,而网上所说的“类锁”并不是对类进行加锁,而是synchronized(XXXX.class)。synchronized是不支持对类、构造方法和静态代码块进行加锁的。

        2、reentranLock

        3、读写锁的使用

        4、自旋锁

        5、信号量实现锁效果


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值