锁机制-1
2016-04-12 19:21:09 5 举报
AI智能生成
J.U.C,锁,加锁,释放锁
作者其他创作
大纲/内容
锁机制-1
1.Lock与ReentrantLock
2.AQS
原子性操作同步器的状态位
阻塞和唤醒线程
LockSupport
一个有序的队列
CHL列表
volatile int waitStatus
CANCELLED = 1: 节点操作因为超时或者对应的线程被interrupt。节点不应该留在此状态,一旦达到此状态将从CHL队列中踢出。
SIGNAL = -1: 节点的继任节点是(或者将要成为)BLOCKED状态(例如通过LockSupport.park()操作),因此一个节点一旦被释放(解锁)或者取消就需要唤醒(LockSupport.unpack())它的继任节点。
CONDITION = -2:表明节点对应的线程因为不满足一个条件(Condition)而被阻塞。
0: 正常状态,新生的非CONDITION节点都是此状态。
非负值标识节点不需要被通知(唤醒)。
volatile Node prev;此节点的前一个节点。节点的waitStatus依赖于前一个节点的状态。
volatile Node next;此节点的后一个节点。后一个节点是否被唤醒(uppark())依赖于当前节点是否被释放。
volatile Thread thread;节点绑定的线程。
Node nextWaiter;下一个等待条件(Condition)的节点,由于Condition是独占模式,因此这里有一个简单的队列来描述Condition上的线程节点。
3.加锁的原理(Lock.lock)
1.ReentrantLock
1.acquire(int)
1)如果tryAcquire(arg)成功,那就没有问题,已经拿到锁,整个lock()过程就结束了。如果失败进行操作2。
2)创建一个独占节点(Node)并且此节点加入CHL队列末尾。进行操作3。
3)自旋尝试获取锁,失败根据前一个节点来决定是否挂起(park()),直到成功获取到锁。进行操作4。
4)如果当前线程已经中断过,那么就中断当前线程(清除中断位)。
2.tryAcquire(acquires)
1)如果当前锁有其它线程持有,c!=0,进行操作2。否则,如果当前线程在AQS队列头部,则尝试将AQS状态state设为acquires(等于1),成功后将AQS独占线程设为当前线程返回true,否则进行2。这里可以看到compareAndSetState就是使用了CAS操作。
2)判断当前线程与AQS的独占线程是否相同,如果相同,那么就将当前状态位加1(这里+1后结果为负数后面会讲,这里暂且不理它),修改状态位,返回true,否则进行3。这里之所以不是将当前状态位设置为1,而是修改为旧值+1呢?这是因为ReentrantLock是可重入锁,同一个线程每持有一次就+1。
3)返回false。
3.addWaiter(mode)
1.独占锁的mode(Condition条件队列)为null
2.共享锁的mode为new node
1)如果当前节点是AQS队列的头结点(如果第一个节点是DUMP节点也就是傀儡节点,那么第二个节点实际上就是头结点了),就尝试在此获取锁tryAcquire(arg)。如果成功就将头结点设置为当前节点(不管第一个结点是否是DUMP节点),返回中断位。否则进行2。
2)检测当前节点是否应该park(),如果应该park()就挂起当前线程并且返回当前线程中断位(是否中断)。如果没有中断则进行操作1。
1)如果前一个节点的等待状态waitStatus==-1,也就是前面的节点还没有获得到锁,那么返回true,表示当前节点(线程)就应该park()了。否则进行2。
。
3)前一个节点等待状态waitStatus=0,修改前一个节点状态位为SINGAL,表示后面有节点等待你处理。进行4。
4)返回false,表示线程不应该park()。
5.selfInterrupt()
Thread.currentThread().interrupt();
4.锁释放与条件变量 (Lock.unlock And Condition)
1.tryRelease(releases)
1)判断持有锁的线程是否是当前线程,如果不是就抛出IllegalMonitorStateExeception(),因为一个线程是不能释放另一个线程持有的锁(否则锁就失去了意义)。否则进行2。
2)将AQS状态位减少要释放的次数(对于独占锁而言总是1),如果剩余的状态位0(也就是没有线程持有锁),那么当前线程就是最后一个持有锁的线程,清空AQS持有锁的独占线程。进行3。
3)将剩余的状态位写回AQS,如果没有线程持有锁就返回true,否则就是false。
2.Condition
await()
1)将当前线程加入Condition锁队列。特别说明的是,这里不同于AQS的队列,这里进入的是Condition的FIFO队列。后面会具体谈到此结构。进行2。
2)释放锁。这里可以看到将锁释放了,否则别的线程就无法拿到锁而发生死锁。进行3。
3)自旋(while)挂起,直到被唤醒或者超时或者CACELLED等。进行4。
4)获取锁(acquireQueued)。并将自己从Condition的FIFO队列中释放,表明自己不再需要锁(我已经拿到锁了)
signal/signalAll
5.备注
以上资料全部来自:http://www.blogjava.net/xylz/archive/2010/07/08/325587.html
收藏
0 条评论
下一页