锁(想办法避免线程进入内核态的阻塞状态是分析和理解锁设计的关键)
悲观锁
实例对象
- 对象头(占用内存大小与虚拟机位长一致,32位JVM -> MarkWord是32位,64位JVM -> MarkWord是64位)
- 类型指针:方法区地址,指向当前对象类型所在方法区中的类型信息,表明是哪个类的实例对象
- MarkWord:hashcode值,锁相关信息,分代信息
- 1.6对锁的优化
- 无锁(检查对象头中是否存储了线程ID,若没有,CAS替换MarkWord将自己的线程ID存储在对象头中,无锁升级为偏向锁)
- 偏向锁(对象头中存储着线程ID)
- 轻量级锁(对象头中的MarkWord为指向线程虚拟机栈中锁记录的指针)
- 重量级锁(用户态与核心态的切换,使线程进入内核态的阻塞状态)
- 1.6对锁的优化
- 实例数据
- 对齐填充
ReentrantLock的lock()方法
- 调用lock()方法
- 调用Sync的lock方法,Sync
Lock接口
-
lock方法(获取锁)
-
lockInterruptibly(获取锁)
-
tryLock(获取锁)
-
boolean tryLock(long time, TimeUnit unit)//尝试多久获取锁
-
unlock//释放锁
-
Condition newCondition()//新建一个绑定在当前Lock对象上的Condition对象
ReentrantLock是Lock接口的实现类
-
private final Sync sync;//成员变量,final修饰,一旦初始化,就不能修改引用了
-
Sync是抽象静态内部类继承自AQS
abstract static class Sync extends AbstractQueuedSynchronizer {
-
NofairSync是静态内部类,非公平锁,不允许被继承
-
static final class NonfairSync extends Sync {
-
FairSync是静态内部类,公平锁,不允许被继承
-
static final class NonfairSync extends Sync {
-
ReentrantLock默认构造方法是非公平锁
-
public ReentrantLock() { sync = new NonfairSync(); }
-
但也可以通过有参构造方法实例化公平锁对象
-
public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
-
调用lock方法获取锁,
-
公平锁
-
调用acquire方法(acquire方法是AQS的final方法,不允许被重写)
-
acquire方法调用tryAcquire方法,acquireQueued方法,addWaiter方法
-
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
-
tryAcquire方法,尝试获取锁,公平锁对AQS的tryAcquire进行重写
-
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
-
当前对象没有线程占用时,判断是否有在当前线程前的线程(公平锁),没有就CAS,将当前独占线程更新为当前线程,当前对象有线程占用时,判断是不是当前线程(可重入锁),最大重入次数,int最大值,一直加就会变成负数
-
-
非公平锁
-
调用lock方法
-
首先CAS获取锁,如果获取成功,将独占对象锁的线程更新为当前线程
-
CAS不成功,则调用acquire方法
-
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
-
acquire是AQS中的final方法,不允许子类对方法进行重写
-
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
-
addWaiter(Node.EXCLUSIVE)方法/为当前线程创建节点,加入等待队列
-
private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } enq(node); return node; }
-
通过当前线程和锁模式创建一个新节点
-
pred指针指向尾节点Tail
-
如果尾节点不是空的,将新建节点的prev指向尾节点,通过CAS完成尾节点的设置
-
如果尾节点是空的,初始化头结点,执行入队流程enq(node)
-
final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
acquireQueued会把放入队列中的线程不断去获取锁,直到获取成功或者不再需要获取(中断)。
-
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
-
当前对象锁没有线程占用的时候,直接CAS,成功的话,将独占对象锁的线程更新为当前线程。如果对象锁已经被线程占用了,则判断是不是当前线程,(可重入锁)
-
-