十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
这篇文章主要介绍了ReentrantLock源码的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
创新互联公司是专业的锦州网站建设公司,锦州接单;提供网站设计、成都网站制作,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行锦州网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
锁是用来控制多个线程访问共享资源的方式,一个锁能够防止多个线程同时共享资源。
Lock需要显式的获取和释放锁,拥有了获取锁和释放锁的可操作性,可中断的获取锁以及超时获取锁等多种同步特性
Lock的实现基本都是通过聚合一个同步器的子类来实现的。
使用一个int变量来表示同步状态
内置一个FIFO队列来完成资源的获取以及线程的排队工作
同步器本身未实现任何同步接口,仅仅是定义了若干同步状态获取和释放的方法来供自定义同步组件使用
即支持独占式获取同步状态,也支持共享式获取同步状态
支持一个线程对资源的重复加锁
再次获取锁:通过判断当前线程是否为获取锁的线程来决定获取操作是否成功,如果是获取锁的线程再次请求,则同步状态增加并返回成功
锁的最终释放:锁被释放时,计数自减,当计数等于0表示锁已经成功释放
读写锁维护了一堆锁,一个读锁,一个写锁。
通过分离读锁和写锁,使并发性相比一般的排它锁有了很大提升,因为大多数场景读多于写
读锁:
支持重进入的共享锁,当前线程获取了写锁或者锁未获取,当前线程增加读状态,成功获取读锁
写锁:
支持重入的排他锁,如果存在读锁,则写锁不能获取
锁降级:指的是写锁降级为读锁
当需要阻塞或者唤醒一个线程的时候,都会使用该工具类来完成相应工作
提供类似Object的监视器方法,与Lock配合实现等待.通知模式
依赖Lock对象,获取一个Condition必须通过Lock的NewCondition()方法
是同步器AbstractQueuedSynchronizer的内部类
每个Condition包含一个队列,该队列是Condition对象实现等待.通知功能的关键
调用await()方法,会使当前线程进入等待队列,并且释放锁,同时线程变成等待状态
调用signal()方法,将会唤醒在队列中等待时间最长的节点
public interface Lock { // 省略大部分代码 /** * Condition 跟Lock绑定 */ Condition newCondition(); } // 通过实现Lock定义的接口,以及聚合一个队列同步器AbstractQueuedSynchronizer实现 public class ReentrantLock implements Lock, java.io.Serializable { private static final long serialVersionUID = 7373984872572414699L; /** Synchronizer providing all implementation mechanics */ private final Sync sync; /** * 定义一个内部类,继承同步器 */ abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; } } /** * 无参数构造方法,默认是非公平锁 */ public ReentrantLock() { sync = new NonfairSync(); } /** * 有参数构造方法,参数传递true,则为公平锁 */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } // 获取Condition是通过Lock内部的方法在调用了同步器内部的方法实现的 public Condition newCondition() { return sync.newCondition(); } public class ReentrantLock implements Lock, java.io.Serializable { private static final long serialVersionUID = 7373984872572414699L; /** Synchronizer providing all implementation mechanics */ private final Sync sync; /** * ...... */ abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; // ...... // 获取Condition对象,是同步器的内部类 final ConditionObject newCondition() { return new ConditionObject(); } // ...... } } // 当锁可用,并且当前线程没有持有该锁,直接获取锁并把count set为1. // 当锁可用,并且当前线程已经持有该锁,直接获取锁并把count增加1. // 当锁不可用,那么当前线程被阻塞,休眠一直到该锁可以获取,然后把持有count设置为1. public void lock() { sync.lock(); } /** * 非公平锁加锁 */ 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)) // 设置当前线程 setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } } // 标识位进行交换 protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); } public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } /** *添加进等待队列 */ final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } } /** * Convenience method to interrupt current thread. */ static void selfInterrupt() { Thread.currentThread().interrupt(); } /** * 公平锁 */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); } /** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */ 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; } } /* * 等待队列是空,或者当前头节点就是当前线程 */ public final boolean hasQueuedPredecessors() { // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); } // 当锁可用,并且当前线程没有持有该锁,直接获取锁并把count set为1. // 当锁可用,并且当前线程已经持有该锁,直接获取锁并把count增加1. // 获取锁时,如果其他线程持有该锁,无可用锁资源,直接返回false,这时候线程不用阻塞等待,可以先去做其他事情 public boolean tryLock() { return sync.nonfairTryAcquire(1); } //当获取锁时,锁资源在超时时间之内变为可用,并且在等待时没有被中断,那么当前线程成功获取锁,返回true,同时当前线程持有锁的count设置为1. // 当获取锁时,在超时时间之内没有锁资源可用,那么当前线程获取失败,不再继续等待,返回false. // 当获取锁时,在超时等待时间之内,被中断了,那么抛出InterruptedException,不再继续等待. // 当获取锁时,在超时时间之内锁可用,并且当前线程之前已持有该锁,那么成功获取锁,同时持有count加1. public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } // 释放锁 public void unlock() { sync.release(1); } /** * 释放锁方法 */ AbstractQueuedSynchronizer.java 的方法 public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; } // ReentrantLock.java的内部类Sync的方法 protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
感谢你能够认真阅读完这篇文章,希望小编分享的“ReentrantLock源码的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持创新互联,关注创新互联行业资讯频道,更多相关知识等着你来学习!