博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java锁之ReentrantLock(一)
阅读量:7136 次
发布时间:2019-06-28

本文共 7368 字,大约阅读时间需要 24 分钟。

一、ReenTrantLock结构

图1-1

根据上图可以知道,ReenTrantLock继承了Lock接口,Lock接口声明方法如下:

方法名 说明 抛出异常
lock() 一直阻塞获取锁,直到获取成功
lockInterruptibly() 尝试获取锁,直到获取锁或者线程被中断 InterruptedException
tryLock() 尝试获取空闲的锁,获取成功返回true,获取失败返回false,不会阻塞,立即返回
tryLock(long time, TimeUnit unit) 尝试在time时间内获取空闲的锁,在等待时间内可以被中断 InterruptedException
unlock() 释放锁
newCondition() 返回当前锁的一个condition实例,用于条件性等待

二、Lock的实现类ReentrantLock

1.ReentrantLock的部分方法

图2-1

  • 根据图2-1可以知道 Sync对象提供了所有的实现机制,而Sync继承了AbstractQueuedSynchronizer
  • NonfairSync 不公平锁,继承了Sync
  • FairSync 公平同步,继承了Sync

1. Sync


Sync是NonfairSync 和FairSync 的父类,声明方法如下:

/**       * 抽象方法,获取锁       */      abstract void lock();      /**       * 实现非公平锁获取逻辑       */      final boolean  nonfairTryAcquire(int acquires) {          final Thread current = Thread.currentThread();          int c = getState(); //父类同步器方法,获取当前同步状态,后续文章会分析          if (c == 0) {//状态等于0表示没有获取到锁              if (compareAndSetState(0, acquires)) { //CAS方式修改状态                  setExclusiveOwnerThread(current); //修改成功后设置当前线程为锁的所有者                  return true;              }          }          else if (current == getExclusiveOwnerThread()) {//当前锁已被占用,判断是不是自己获取到了锁,锁重入              int nextc = c + acquires; //获取锁的计数器              if (nextc < 0) // overflow //因为是int类型,如果超过int最大值会溢出为负                  throw new Error("Maximum lock count exceeded");              setState(nextc);//设置计数器为状态值              return true;          }          return false;      }      protected final boolean tryRelease(int releases) {          int c = getState() - releases;//释放锁,同步状态减int值          if (Thread.currentThread() != getExclusiveOwnerThread())              throw new IllegalMonitorStateException(); //如果当前相差不是锁的拥有者,抛出异常          boolean free = false;          if (c == 0) { //如果同步状态值为0,表示锁已经释放成功              free = true;               setExclusiveOwnerThread(null); // 设置锁的拥有线程为null          }          setState(c);//重新赋值同步状态          return free;      }      //判断当前线程是不是锁独占      protected final boolean isHeldExclusively() {                  return getExclusiveOwnerThread() == Thread.currentThread();      }      //返回锁的ConditionObject实例      final ConditionObject newCondition() {          return new ConditionObject();      }      // Methods relayed from outer class      //获取当前占有锁的线程      final Thread getOwner() {          return getState() == 0 ? null : getExclusiveOwnerThread();      }      //获取当前锁计数      final int getHoldCount() {          return isHeldExclusively() ? getState() : 0;      }      //判断是否获取到锁      final boolean isLocked() {          return getState() != 0; //可以知道判断获取锁的关键就是是否不等于0      }复制代码

2. NonfairSync 非公平锁


static final class NonfairSync extends Sync {       private static final long serialVersionUID = 7316153563782823691L;       /**        * Performs lock.  Try immediate barge, backing up to normal        * acquire on failure.        */       final void lock() {           if (compareAndSetState(0, 1))//CAS获取锁               setExclusiveOwnerThread(Thread.currentThread());           else               acquire(1);       }       protected final boolean tryAcquire(int acquires) {           return nonfairTryAcquire(acquires);       }   }复制代码
  • 根据源码发现 非公平锁继承了Sync父类,由于锁的释放不存在公平与不公平,所以公平锁和非公平锁只实现各自获取锁的逻辑。根据非公平锁的源码发现,其内部只实现了lock()tryAcquire(int acquires)方法,其中和tryAcquire(int acquires)方法直接调用了父类的nonfairTryAcquire(acquires),介绍父类的时候已经解析过,不清楚可以看上文Sync解析部分。根据lock源码发现,开始判断是否是第一次获取锁,如果获取锁成功,就把当前线程设置为锁的占有者,否则调用父类的acquire(1)方法(下一篇介绍同步器会介绍)。

3. FairSync 公平锁


static final class FairSync extends Sync {        private static final long serialVersionUID = -3000897897090466540L;        /**调用父类的acquire()方法*/        final void lock() {            acquire(1);        }        /**         * 尝试获取锁         */        protected final boolean tryAcquire(int acquires) {            final Thread current = Thread.currentThread();            int c = getState();            if (c == 0) {                if (!hasQueuedPredecessors() &&                    compareAndSetState(0, acquires)) {                    setExclusiveOwnerThread(current);                    return true;                }            }            else if (current == getExclusiveOwnerThread()) {                int nextc = c + acquires;                if (nextc < 0)                    throw new Error("Maximum lock count exceeded");                setState(nextc);                return true;            }            return false;        }    }复制代码
  • 根据上面代码发现公平锁的获取代码和非公平锁获取锁代码很相识,公平锁只多了一个 !hasQueuedPredecessors()判断,其实该方法就是判断是否有比当前线程等待最长时间的线程,如果没有,那么就尝试获取锁,获取成功后设置当前线程为锁的占有者,所以,公平与不公平就是是否按照时间等待来获取锁的,比如食堂吃饭,排队一个个来,这就是公平,如果有人插队,这就是不公平。

3. ReentrantLock 其他方法


public ReentrantLock() {        sync = new NonfairSync();    }public ReentrantLock(boolean fair) {        sync = fair ? new FairSync() : new NonfairSync();    }  public void lock() {        sync.lock();    } public void lockInterruptibly() throws InterruptedException {        sync.acquireInterruptibly(1);    }public boolean tryLock() {        return sync.nonfairTryAcquire(1);    }    //指定超时时间内获取锁,阻塞时间为timeout public boolean tryLock(long timeout, TimeUnit unit)            throws InterruptedException {        return sync.tryAcquireNanos(1, unit.toNanos(timeout));    } public Condition newCondition() {        return sync.newCondition();    }public int getHoldCount() {        return sync.getHoldCount();    }  public boolean isHeldByCurrentThread() {        return sync.isHeldExclusively();    } public final boolean isFair() {        return sync instanceof FairSync;    }protected Thread getOwner() {        return sync.getOwner();    }public final boolean hasQueuedThreads() {        return sync.hasQueuedThreads();    }  public final boolean hasQueuedThread(Thread thread) {        return sync.isQueued(thread);    }public final int getQueueLength() {        return sync.getQueueLength();    }protected Collection
getQueuedThreads() { return sync.getQueuedThreads(); } public boolean hasWaiters(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); } public int getWaitQueueLength(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); } protected Collection
getWaitingThreads(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); }复制代码
  • 其实根据上面源码发现,不管是实现LOCK接口的方法,还是后续新增的方法,其实现功能都依托于一个对象,那就是sync,在介绍sync时候已经说过,它就是继承了AbstractQueuedSynchronizer同步器,很多方法都是直接调用父类同步器的方法,下一篇《java锁之ReentrantLock(二)》会重点解析AbstractQueuedSynchronizer同步器源码,分析同步器是如何依托于FIFO队列完成锁的机制。

三、 总结

  • ReentrantLock实现了LOCK接口
  • ReentrantLock可以实现公平锁和非公平锁获取
  • ReentrantLock可以进行超时时间内获取锁
  • ReentrantLock可以进行条件等待和唤醒
  • ReentrantLock可以获取锁响应中断

转载地址:http://hmvrl.baihongyu.com/

你可能感兴趣的文章
HTTP协议入门知识
查看>>
SQL中创建用户的方法
查看>>
PHP168 6.0及以下版本login.php代码执行
查看>>
Java代理(jdk静态代理、动态代理和cglib动态代理)
查看>>
WPF生命周期
查看>>
各大Oj平台介绍
查看>>
hdu1059 dp(多重背包二进制优化)
查看>>
四象限分析法分析你是否适合做管理
查看>>
Create a database in mysql for mac
查看>>
史上最全、JavaScript基础篇
查看>>
Selenium Web 自动化 - Selenium常用API
查看>>
第13天:页面布局实例-博雅主页
查看>>
javascript基础
查看>>
jquery获取、改变元素属性值
查看>>
关闭VirtualBox虚拟机的时钟同步
查看>>
剪贴板(进程通信)
查看>>
删除链表中重复的结点
查看>>
查看你的电脑上.Net Framework版本的方法
查看>>
java编程目录
查看>>
Java读取xml
查看>>