1 Lock接口 Lock和synchronized有何区别,区别在于synchronized是锁一个代码块或一个方法,需要先获取锁再释放锁,可操作性比不上Lock。而Lock的可操作性在于我们可以像下面这样操作: ------------------------------------------------------ Lock lock1 = new ReentrantLock(); Lock lock2 = new ReentrantLock(); lock1.lock(); lock2.lock(); lock1.unlock(); lock2.unlock(); ------------------------------------------------------ 分析:以上代码说明了Lock的可操作性,lock1拿到了锁,然后lock2获取到了锁后释放lock1锁,可以将锁一层嵌套一层,可操作性比synchronized强。 2 队列同步器 队列同步器AbstractQueuedSynchronizer,简称AQS 其作为java.util.concurrent包下不少类如(ReentrantLock,CountDownLactch等)的锁或同步组件的基础。内部维护了一个state状态+队列用于处理并发的请求。 同步器提供了模板方法,其模板方法分为如下三类: 独占式获取和释放同步状态(state) tryAcquire()、tryRelease() 共享式获取和释放同步状态(state) tryAcquireShared()、tryReleaseShared() 查询同步队列等待线程情况 isHeldExclusively() 可用于继承实现自己的同步组件,其实现代码如下: public class Mutex implements Lock { // 静态内部类,自定义同步器 private static class Sync extends AbstractQueuedSynchronizer { // 是否处于占用状态 @Override protected boolean isHeldExclusively() { return getState() == 1; } // 当状态为0的时候获取锁 @Override protected boolean tryAcquire(int acquires) { if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } // 释放锁,将状态设置为0 @Override protected boolean tryRelease(int releases) { if(getState() == 0) throw new IllegalMonitorStateException(); setExclusiveOwnerThread(null); setState(0); return true; } // 返回一个Condition,每个condition都包含了一个condition队列 Condition newCondition() { return new ConditionObject(); } } // 仅需要将操作代理到Sync上即可 private final Sync sync = new Sync(); @Override public void lock() { sync.acquire(1); } @Override public boolean tryLock() { return sync.tryAcquire(1); } @Override public void unlock() { sync.release(1); } @Override public Condition newCondition() { return sync.newCondition(); } public boolean isLocked() { return sync.isHeldExclusively(); } public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } @Override public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } @Override public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } } 分析:首先使用一个类实现了Lock接口,然后在内部实现一个Sync(继承AQS)同步组件。最后通过调用同步组件的方法来达到同步的目的。 其部分源码链接可见文章: https://blog.csdn.net/qq_28666081/article/details/90490369 3 可重入锁 支持重新进入的锁,该锁支持一个线程对资源的重复加锁。其中synchronized和ReentrantLock都支持可重入锁。 另外,锁有一个公平性,等待越久的线程约会先获取锁(顺序FIFO获取),避免"饥饿"现场(ReentrantLock可控制是否公平锁)。 实现重进入 什么是重进入? 任意线程获取锁之后,能够再次获取锁而不会被阻塞 // 以下是详细代码=============================== final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState();// 1 如果非获取到锁的线程,获取状态 if (c == 0) { // 如果状态为空则释放了所有,当前新的线程可索取锁 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { // 2 如果当前线程是那个拿到锁的线程,就直接进入,并且给他的状态值自增 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } // 上面因为当前拥有锁的再次进入会增加state值大小,所以需要在释放的时候进行处理 protected final boolean tryRelease(int releases) { int c = getState() - releases; //1 state减去释放的值 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { //如果当前state=0,那就是真的释放操作,并且使用setExclusiveOwnerThread释放 free = true; setExclusiveOwnerThread(null); } setState(c); return free; } 4 读写锁(不讲解,感兴趣可自行学习) Java中读写锁一般指的是 ReentrantReadWriteLock,可将读写分离,可多次重复读(共享),但是写的时候是互斥(排他)的。 ReentrantReadWriteLock自定义了同步器,通过同步器状态维护了多个读线程 + 一个写线程。 5 LockSupport工具 方法如下: 使用例子如下: //获取当前线程 final Thread currentThread = Thread.currentThread(); //在park之前先进行一次unpark LockSupport.unpark(currentThread); System.out.println("开始阻塞!"); // 由于在park之前进行了一次unpark,所以会抵消本次的park操作。因而不会阻塞在此处 LockSupport.park(currentThread); System.out.println("结束阻塞!"); 参考文章: https://www.jianshu.com/p/ceb8870ef2c5 6 Condition接口 当前接口用于 通知/等待,但是操作前均需要获取锁,是基于lock接口来实例化的。 Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); public void conditionWait() throws InterruptedException { lock.lock(); //使用前先获取锁 try { condition.await(); //释放锁并进入阻塞状态 } finally { lock.unlock(); } } public void conditionSignal() throws InterruptedException { lock.lock(); try { condition.signal(); //通知获取锁 } finally { lock.unlock(); } } 实现分析(以下是ConditionObject源码,分析Condition时均以这个说明,其入口在ReentrantLock.newCondition()): // 1 调用await时 public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); // await时,当前线程会先进入等待队列 Node node = addConditionWaiter(); // 然后释放同步状态,也就是释放对应的锁 int savedState = fullyRelease(node); int interruptMode = 0; // 然后唤醒同步队列后继节点 while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); } // 2 调用signal唤醒 public final void signalAll() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; // 因为await时会加新的线程加入等待队列尾节点,所以首节点是加入最久的,这时候唤醒的话会取首节点(等最久的)去唤醒 if (first != null) doSignalAll(first); } // 最后`signal`还是调用了以下方法来进行唤醒,LockSupport.unpark(thread); public static void unpark(Thread thread) { if (thread != null) UNSAFE.unpark(thread); }