民政局网站建设工作总结我想建一个网站怎么建
民政局网站建设工作总结,我想建一个网站怎么建,wordpress 主题窜改,如何推广平台在多线程并发编程中#xff0c;我们都学过synchronized关键字#xff0c;但它就像黑盒子的自动锁#xff1a;你不知道谁在排队#xff0c;不能中断等待#xff0c;也无法设置超时。2004年#xff0c;Java 5引入的ReentrantLock#xff08;可重入锁#xff09;#xff…在多线程并发编程中我们都学过synchronized关键字但它就像黑盒子的自动锁你不知道谁在排队不能中断等待也无法设置超时。2004年Java 5引入的ReentrantLock可重入锁底层依托AbstractQueuedSynchronizerAQS将锁的本质从系统级隐式管理变成了对象级显式控制。今天我们从源码层面拆解这行代码背后发生了什么lock.lock(); // 这行代码到底垄断了什么资源一、核心架构AQS——锁的大后台ReentrantLock本身并不直接实现锁逻辑而是委托给内部类Sync继承自AQS。这就像消息队列前两篇文章提到的MQ将存储引擎和协议解耦。1.1 AQS的三根顶梁柱AQSAbstractQueuedSynchronizer是一个CLH变体队列状态机的框架核心字段类型作用类比statevolatile int资源计数器0无人占用1被占1重入次数像在餐厅占座一个人占座但点了3道菜exclusiveOwnerThreadThread独占线程标记记录当前谁拿着锁老板的名字写在座位上head/tailNode双向队列排队等待的线程等位区的顾客名单// AQS核心结构位于java.util.concurrent.locks.AbstractQueuedSynchronizerpublic abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer { private volatile int state; // 同步状态 private transient volatile Node head; // 队头虚节点 private transient volatile Node tail; // 队尾 // ...}二、加锁源码走读非公平锁的抢票逻辑ReentrantLock默认是非公平锁NonfairSync允许插队。这像不像你消息队列那篇文章里说的流量削峰不这更像是有人不排队直接挤到窗口前。2.1 第一次CAS尝试快速路径// ReentrantLock.NonfairSync.lock()final void lock() { // 1. 先无脑CAS抢一次0→1成功就占有锁 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); // 失败就进入正常流程}图解就像进餐厅先看有没有空桌state0有就直接坐CAS成功没有才取号排队。2.2 acquire的标准流程AQS模板方法如果第一次没抢到进入acquire(1)这是模板方法模式// AQS.acquire() - 模板方法定义了加锁流程框架public final void acquire(int arg) { // 1. tryAcquire子类实现尝试获取 // 2. addWaiter入队包装成Node加入CLH队列尾部 // 3. acquireQueued在队列里自旋阻塞等待 if (!tryAcquire(arg) acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt();}步骤1tryAcquire——子类的个性定制NonfairSync的实现// 非公平锁的尝试获取protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires);} final boolean nonfairTryAcquire(int acquires) { final Thread current Thread.currentThread(); int c getState(); if (c 0) { // 哪怕有队列也再CAS抢一次非公平的精髓 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current getExclusiveOwnerThread()) { // **可重入性**同一线程再次获取state1 int nextc c acquires; if (nextc 0) // overflow throw new Error(Maximum lock count exceeded); setState(nextc); return true; } return false;}关键设计可重入通过判断current owner避免自己把自己锁死就像你家门锁你拿钥匙进去后在屋里可以再锁一次而不会卡死非公平c0时直接CAS不看队列前面有没有人步骤2addWaiter——封装成节点入队private Node addWaiter(Node mode) { Node node new Node(Thread.currentThread(), mode); Node pred tail; // 快速入队CAS设置tail if (pred ! null) { node.prev pred; if (compareAndSetTail(pred, node)) { pred.next node; return node; } } enq(node); // 竞争失败后的慢速入队自旋CAS return node;}结构特性双向链表prev前驱和next后继虚拟头节点head始终是一个Thread为null的占位节点哨兵节点步骤3acquireQueued——队列中的自旋阻塞final boolean acquireQueued(final Node node, int arg) { boolean failed true; try { boolean interrupted false; for (;;) { // 自旋spin final Node p node.predecessor(); // 只有前驱是head时才有资格tryAcquire防止全面惊群 if (p head tryAcquire(arg)) { setHead(node); // 抢到后把自己设为虚head p.next null; // help GC failed false; return interrupted; } // shouldParkAfterFailedAcquire检查是否需要睡觉 // parkAndCheckInterrupt挂起线程调用LockSupport.park if (shouldParkAfterFailedAcquire(p, node) parkAndCheckInterrupt()) interrupted true; } } finally { if (failed) cancelAcquire(node); // 异常时清理节点 }}精妙之处只有前驱是head才尝试获取避免所有线程一起抢与synchronized的惊群效应相比这像消息队列的顺序消费自旋→阻塞先自旋几次短时等待实在拿不到才调用LockSupport.park()挂起切换到内核态省CPU三、解锁源码state减到0才算真释放加锁是state解锁就是state--减到0才算真正释放。// ReentrantLock.unlock() → AQS.release()public final boolean release(int arg) { if (tryRelease(arg)) { // 1. 先尝试释放子类实现 Node h head; // 2. 如果队列不为空且需要唤醒waitStatus≠0叫醒后继 if (h ! null h.waitStatus ! 0) unparkSuccessor(h); return true; } return false;}tryRelease在Sync中的实现protected final boolean tryRelease(int releases) { int c getState() - releases; // 减去释放量通常是1 // 只有锁的持有者才能释放防君子不防小人但也判一下 if (Thread.currentThread() ! getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free false; if (c 0) { // 完全释放重入计数归零 free true; setExclusiveOwnerThread(null); // 擦除 owner 标记 } setState(c); // 不是volatile操作不setState内部是volatile写 return free;}唤醒机制private void unparkSuccessor(Node node) { int ws node.waitStatus; if (ws 0) compareAndSetWaitStatus(node, ws, 0); // 清掉SIGNAL标志 Node s node.next; if (s null || s.waitStatus 0) { // 后继已取消或为空 s null; for (Node t tail; t ! null t ! node; t t.prev) if (t.waitStatus 0) s t; // 从后往前找最近的正常节点 } if (s ! null) LockSupport.unpark(s.thread); // 叫醒排队最靠前的那个}注意唤醒是从后往前找有效节点因为next指针可能还没设置好enq时是先设prevCAS tail再设next而prev是稳定的。四、公平锁 vs 非公平锁要不要走后门就像你消息队列文章里说的应用解耦这里AQS通过模板方法解耦了排队策略维度NonfairSync默认FairSynctryAcquire逻辑c0时直接CAS抢c0时先检查hasQueuedPredecessors()有排队线程就让性能吞吐量大线程切换少吞吐量略低但防止饥饿使用场景普通业务锁如计数器避免线程饥饿如文件IO等待公平锁的额外判断// FairSync.tryAcquireif (c 0) { // 关键差别先看有没有前驱节点在排队 if (!hasQueuedPredecessors() compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; }}五、与synchronized的终极对决特性ReentrantLocksynchronizedJVM层面实现层Java代码SDK CAS LockSupportJVM monitorenter/exit 对象头Mark Word等待队列显式AQS双向队列对象头的_WaitSetC实现不可见可中断lockInterruptibly()支持中断不可中断Io阻塞除外超时tryLock(long timeout, TimeUnit unit)不支持条件队列多条件变量newCondition()可创建多个单一wait/notifyAll性能Java 6后两者性能接近AQS的优化JIT编译后偏向锁/轻量级锁优化六、总结AQS的设计哲学ReentrantLock的源码其实展示了模板方法模式在并发框架中的极致应用状态与队列分离state管资源Node管排队职责单一CAS自旋优化先用用户态自旋抢不行再进内核态park避免线程切换开销可重入友好state计数器天然支持同线程递归加锁变体灵活公平/非公平只需覆盖tryAcquire复用AQS的排队基础设施消息队列文章中说的引入MQ之后系统和系统间只需要依赖于MQ而无需进行直接依赖。 AQS也是如此——所有并发工具Semaphore、CountDownLatch、ReentrantReadWriteLock只需依赖AQS的状态和队列机制而不必重复造轮子。