Synchronized是独占锁,性能低,Lock借助JNI完成的高级锁实现。Lock接口实现的锁比synchronize的锁更加广泛,实现了更加灵活地操作,支持多个Condition对象。
Lock接口下提供的方法:void lock();void lockInterruptibly();condition newCondition();boolean tryLock();boolean tryLock(long time,TimeUnit unit);void unLock()。
lock():获取锁时,如果锁不可用时线程则进入休眠。
void lockInterruptibly() throws InterruptedException :如果当前线程不发生中断,则获取锁,否则,在锁被其他线程所持有的情况下,会进入休眠。
newCondition():返回绑定到此Lock实例上的新的Condition实例,Condition实例是可以进行线程间通信的。
tryLock():尝试性获取锁,仅在锁空闲时才能获取锁,如果锁可用,则立即获取锁,返回true,如果锁不可用,则返回false,通常对于不是必要必须获取锁的操作可能有用。
tryLock(long time,TimeUnit unit) throws InterrupteException:在一定时间内尝试性的获取锁,如果锁在给定的等待时间内空闲,并且当前的线程未被中断,则可以后去锁,如果锁可用,则立即获取锁,返回true,如果锁不可用,则返回false;
如果锁由当前线程获取,或者在其他线程中断当前的线程,并且支持锁获取的中断,或者是在已超过指定的等待时间的情况下,线程会进入休眠。
void unLock():释放锁。
(AQS)AbstractQueuedSynchronize是实现ReentrantLock的前提,公平性锁和非公平锁,以及condition对象进行线程间通信的基础。
AQS的三个主要属性:
private transient volatile Node head; private transient volatile Node tail; //Node类型的队列(先进先出) private volatile int state; //描述的是有多少线程获取锁;如果state等于0,表示锁空闲,大于0表示锁被占用,并且表示被线程占用的次数,小于0表示溢出。
Node类型的主要属性:
static final Node SHARED = new Node(); //共享锁 static final Node EXCLUSIVE = null; //独占锁 static final int CANCELLED = 1; //线程被取消(线程被interrupt操作或者超时),提出队列。 static final int SIGNAL = -1; //当前节点的后续节点包含的线程需要被执行,也就是unpark节点的继承节点或将要成为blocked状态的线程,一旦获取锁的线程释放锁之后,就需要唤醒当前节点的后续节点。 static final int CONDITION = -2;//当前节点在等待Condition,在Condition队列中,表明节点对应的线程不满足codition条件而被阻塞 static final int PROPAGATE = -3; //后续的acquireShared能够得以执行 volatile int waitStatus; //节点的等待状态,包括以上四种,当其等于0时,表示当前的节点在sync队列,等待着获取锁,正常的状态,新产生的非Condition节点都是此状态 volatile Node prev; //表示当前节点的前一个节点,节点的waitStatus依赖前一个节点的状态 volatile Node next; //当前节点的后一个节点 volatile Thread thread; //被包装的线程 Node nextWaiter; //下一个等待条件(Condition)的节点
AQS的原理是实现了一个同步器,同步器支持两个主要操作:
获取锁:
首先判断当前的状态是否允许获取锁,如果是则直接获取锁,否则就则塞操作或者获取失败,如果是独占锁就可能会阻塞,如果是共享锁就可能失败,如果是阻塞线程,那么线程就会进入阻塞队列,当状态为允许获取锁修改状态,并且从阻塞队列里删除掉。
释放锁:
这个过程就是修改状态位,如果有线程因为状态位则塞的话就会唤醒队列中的一个或者更多线程。
支持以上操作必须满足以下条件:
原文:https://www.cnblogs.com/128-cdy/p/12615325.html