java中的锁

介绍:

ReentrantLock,可重入锁,是一种递归无阻塞的同步机制。它可以等同于 synchronized 的使用,但是 ReentrantLock 提供了比 synchronized 更强大、灵活的锁机制,可以减少死锁的发生,同时ReentrantLock还可以实现公平锁机制

  1. 可重入:广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。ReentrantLock和synchronized都是可重入锁
  2. 公平锁 /非公平锁:公平锁与非公平锁的区别在于,公平锁的锁获取是有顺序的。但是公平锁的效率没有非公平锁的效率高,在许多线程访问的情况下,公平锁表现出较低的吞吐量
    注:ReentrantLock默认非公平锁*
公平锁   new ReentrantLock(true)
非公平锁   new ReentrantLock()

读写锁(ReentrantReadWriteLock):

  1. 如果当前没有写锁或读锁时,第一个获取锁的线程都会成功,无论该锁是写锁还是读锁。
  2. 如果当前已经有了读锁,那么这时获取写锁将失败,获取读锁有可能成功也有可能失败
  3. 如果当前已经有了写锁,那么这时获取读锁或写锁,如果线程相同(可重入),那么成功;否则失败

一把读写锁具备三种状态:

  1. 读模式下加锁状态 (读锁)
  2. 写模式下加锁状态 (写锁)
  3. 不加锁状态

读写锁使用:

public class Demo {
 
    private Map<String, Object> map=new HashMap<>();
    private ReadWriteLock rwl=new ReentrantReadWriteLock();
     
    private Lock r=rwl.readLock();
    private Lock w=rwl.writeLock();
     
    public Object get(String key){
        r.lock();
        System.out.println(Thread.currentThread().getName()+"读操作正在执行。。。");
        try {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return map.get(key);
        } finally{
            r.unlock();
            System.out.println(Thread.currentThread().getId()+"读操作执行完毕。。。");
        }
    }
    public void put(String key,Object value){
        w.lock();
        System.out.println(Thread.currentThread().getName()+"写操作在执行。。。");
        try {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            map.put(key, value);
        } finally  {
            w.unlock();
            System.out.println(Thread.currentThread().getName()+"写操作执行完毕。。。");
        }
    }
}

锁的降级
如果当先线程是写锁的持有者,并保持获得写锁的状态,同时又获取到读锁,然后释放写锁的过程。(注意不同于这样的分段过程:当前线程拥有写锁,释放掉写锁之后再获取读锁的过程,这种分段过程不能称为锁降级)

class CachedData {
  Object data;
  volatile boolean cacheValid;
  final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

  void processCachedData() {
    // 获取读锁
    rwl.readLock().lock();
    if (!cacheValid) {
      // 在获取写锁之前必须释放读锁,不释放的话下面写锁会获取不成功,造成死锁
      rwl.readLock().unlock();
     // 获取写锁
      rwl.writeLock().lock();
      try {
        // 重新检查state,因为在获取写锁之前其他线程可能已经获取写锁并且更改了state
        if (!cacheValid) {
          data = ...
          cacheValid = true;
        }
        // 通过在释放写锁定之前获取读锁定来降级
        // 这里再次获取读锁,如果不获取,那么当写锁释放后可能其他写线程再次获得写锁,导致下方`use(data)`时出现不一致的现象
        // 这个操作就是降级
        rwl.readLock().lock();
      } finally {
        rwl.writeLock().unlock(); // 释放写锁,由于在释放之前读锁已经被获取,所以现在是读锁获取状态
      }
    }

    try {
    // 使用完后释放读锁
      use(data);
    } finally {
      rwl.readLock().unlock(); //释放读锁
    }
  }
 }}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值