标签:
最常用的方式:
int a = 12; //注意:通常情况下,这个会设置成一个类变量,比如说Segement中的段锁与copyOnWriteArrayList中的全局锁 final ReentrantLock lock = new ReentrantLock(); lock.lock();//获取锁 try { a++;//业务逻辑 } catch (Exception e) { }finally{ lock.unlock();//释放锁 }
注:关于lock()方法的源码解析,请参照"第五章 ReentrantLock源码解析1--获得非公平锁与公平锁lock()",具体链接如下:
http://www.cnblogs.com/java-zhao/p/5131544.html
释放锁:unlock()
步骤:
1)获取当前的锁数量,然后用这个锁数量减去解锁的数量(这里为1),最后得出结果c
2)判断当前线程是不是独占锁的线程,如果不是,抛出异常
3)如果c==0,说明锁被成功释放,将当前的独占线程置为null,锁数量置为0,返回true
4)如果c!=0,说明释放锁失败,锁数量置为c,返回false
5)如果锁被释放成功的话,唤醒距离头节点最近的一个非取消的节点
源代码:
ReentrantLock:unlock()
/** * 释放这个锁 *1)如果当前线程持有这个锁,则锁数量被递减 *2)如果递减之后锁数量为0,则锁被释放。 *如果当前线程不持久有这个锁,抛出异常 */ public void unlock() { sync.release(1); }
AbstractQueuedSynchronizer:release(int arg)
/** * 释放锁(在独占模式下) */ public final boolean release(int arg) { if (tryRelease(arg)) {//如果成功释放锁 Node h = head;//获取头节点:(注意:这里的头节点就是当前正在释放锁的节点) if (h != null && h.waitStatus != 0)//头结点存在且等待状态不是取消 unparkSuccessor(h);//唤醒距离头节点最近的一个非取消的节点 return true; } return false; }
Sync:tryRelease(int releases)
/** * 释放锁 */ 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); }//如果不为0,怎么办,不释放了吗? setState(c); return free; }
AbstractQueuedSynchronizer:unparkSuccessor(Node node)
/** * 唤醒离头节点node最近的一个非取消的节点 * @param node 头节点 */ private void unparkSuccessor(Node node) { /* * 将当前节点node的状态(如果<0的话)改为0,这个不知道有什么必要, * node节点就是头节点,在下边的代码中头节点都要被替换了,也就是说node节点就要被踢出队列了, * 这个时候还有什么必要去改他的状态吗? */ int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); /* * 获取头节点的下一个等待状态不是cancel的节点 */ Node s = node.next;//头节点的下一个节点 if (s == null || s.waitStatus > 0) { s = null; /* * 注意:从后往前遍历找到离头节点最近的一个非取消的节点,从后往前遍历据说是在入队(enq())的时候,可能nodeX.next==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);//唤醒离头节点最近的一个非取消的节点 }
注意:
在程序的注释部分有一些疑问,整理成下边这样:
第一个问题答案:
可重入性体现在下边这个程序(就是锁套锁,最常见的就是在递归中):
final ReentrantLock lock = new ReentrantLock(); public void add(){ lock.lock();//获取锁 try { add();//业务逻辑 } catch (Exception e) { }finally{ lock.unlock();//释放锁 } }
注意:
第二个问题答案:
还在研究(望大神指导)
第三个问题答案
还在研究(望大神指导)
第六章 ReentrantLock源码解析2--释放锁unlock()
标签:
原文地址:http://www.cnblogs.com/java-zhao/p/5133402.html