jvm对锁的支持看这一篇锁与内存模型
ReentrantLock是一个可重入的互斥锁,于synchronized字段具有相同 的语义和表现。
ReentrantLock执行lock方法,如果这个锁没有被其它线程获取,那么可以成功获取锁。如果当前线程已经持有锁,这个方法会直接返回。检查当前线程是否持有锁的方式是通过isHeldByCurrentThread和getHoldCount。
构造函数接收一个可选参数,决定是使用公平锁还是非公平锁。当设为true时,锁倾向于等待时间最长的线程。否则锁不保证特定的访问顺序。
程序如果使用公平锁,将会导致更低的吞吐量(相对于默认设置,也就是非公平锁),但是也保证了所有线程获取锁的时间的均衡,不会有一些线程等待时间过长。
tryLock()不会去在意公平锁的设置,一旦锁可用,线程会立刻获取锁,即使有其它线程在等待。
1
2推荐在lock.lock()后立马跟上一个try catch。
一个线程可重入这个锁2147483647次,超过这个次数会抛出ERROR。
ReentrantLock的作用是实现代码段的并发访问,它没有直接使用锁,而是一个普通的类实现锁的定义。它提供了可轮询的锁请求,可以规避死锁的发生。
一般情况下,它的性能比synchronized好,它的功能也更全面。提供了condition,对线程的等待和唤醒更灵活,而且可以同时持有多个condition,扩展性更好。
ReentractLock中持有一个sync(AQS)锁,sync有2种实现:公平锁和非公平锁。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45Sync类继承AbstractQueuedSynchronizer abstract static class Sync extends AbstractQueuedSynchronizer { /** 释放锁 */ protected final boolean tryRelease(int releases) { int c = getState() - releases;//state减一层 if (Thread.currentThread() != getExclusiveOwnerThread())//当前线程不是锁的持有者时,抛异常 throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true;//state=0,锁完全被释放 setExclusiveOwnerThread(null);//设置锁的持有者为null } setState(c);//更新锁状态(被持有层数) return free; } /** 判断当前线程是否是锁的持有者 */ protected final boolean isHeldExclusively() { return getExclusiveOwnerThread() == Thread.currentThread(); } final ConditionObject newCondition() { return new ConditionObject(); } /** 获取锁的持有线程 */ final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } /** 获取当前线程持有该锁的层数 */ final int getHoldCount() { return isHeldExclusively() ? getState() : 0; } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // 重置锁到未锁定的状态 } }
公平锁的实现:
公平锁有排队机制,等待的线程可以用队列实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); } public final void acquire(int arg) { if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt();//线程处于中断状态,那么自我中断 } /** * 尝试占有锁 */ protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) {//当前状态,锁未被任何线程持有 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { /* public final boolean hasQueuedPredecessors() {//看当前队列是否是等待队列中,最前面的线程,如果是的haunted,就持有锁,不是的话,获取锁失败。 Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); } */ 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; } }
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22final 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); } }
shouldParkAfterFailedAcquire,判断当前节点的前一个节点,一般第一次判断会返回false,第二次会返回true。也就是说第二次走到这里,线程会阻塞。
parkAndCheckInterrupt()方法会阻塞当前线程,直到被unpark,被唤醒后会检查线程是否被中断过。
1
2
3
4
5
6
7public static void park(Object blocker) { Thread t = Thread.currentThread(); setBlocker(t, blocker);//使当前线程t的parkBlocker=blocker (reentranLock对象) UNSAFE.park(false, 0L);//阻塞当前线程,直到被unpark或者被中断 setBlocker(t, null); }
addWaiter方法:先尝试直接入队,如果成功则返回当前线程节点。否则使用enq方法,CAS方法循环尝试入队。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15private 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; }
公平锁的tryAcquire,判断当前锁的状态,使用CAS获取,不保证一定成功获取锁。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21protected 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; } }
非公平锁的实现
非公平锁会先尝试占用2次,如果失败,则入队列,再检查并尝试(尝试的前提是当前线程在队列头部)2次,失败后进入阻塞。
一旦有机会占用锁,就直接占用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19final 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; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21static final class NonfairSync extends Sync { final void lock() { if (compareAndSetState(0, 1))//锁未被持有,直接占用 setExclusiveOwnerThread(Thread.currentThread()); else acquire(1);//锁已被持有,尝试占用。 /** public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt();//获取锁失败,自我中断,并把自己添加到等待队列的尾部 } */ } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }
获取锁,具体流程看是公平锁还是非公平锁。
1
2
3
4public void lock() { sync.lock(); }
获取锁,除非当前线程被中断。和上面的对比,如果用的是公平锁,只多了开头的中断检查;如果是非公平锁,则多了开头的中断检查以及少了一次最初的CAS获取锁的操作。
1
2
3
4public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); }
无视公平锁和非公平锁的配置,直接尝试获取锁,如果锁没被其它线程持有,返回true,否则返回false。
不会导致线程挂起。
1
2
3
4public boolean tryLock() { return sync.nonfairTryAcquire(1); }
先按照sync的tryAcquire策略尝试一次,失败后进入doAcquireNanos的流程(入waiters队列,在指定时间timeout内尝试获取2次,失败后,休眠至剩余的时间(剩余可休眠时间要大于1000纳秒)后唤醒再尝试一次,如果还是失败则返回false)。
1
2
3
4
5
6public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); }
释放锁,释放了持有的所有层数时,会唤醒下一个线程。如果当前线程没有持有锁,那么会抛出异常。没释放完的话,会返回false。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public void unlock() { sync.release(1); } public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; } protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
唤醒队列中的下一个线程,最靠前的且不是处于取消状态的。并将node的状态更新为0.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17private void unparkSuccessor(Node node) { int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); 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); }
获取当前线程持有锁的层数
1
2
3
4public int getHoldCount() { return sync.getHoldCount(); }
当前线程是否持有锁
1
2
3
4public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); }
锁是否被锁定
1
2
3
4public boolean isLocked() { return sync.isLocked(); }
获取锁的持有线程
1
2
3
4protected Thread getOwner() { return sync.getOwner(); }
检查队列中是否有线程
1
2
3
4public final boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
队列中是否有线程thread
1
2
3
4public final boolean hasQueuedThread(Thread thread) { return sync.isQueued(thread); }
队列中线程的个数
1
2
3
4
5
6
7
8
9public final int getQueueLength() { int n = 0; for (Node p = tail; p != null; p = p.prev) { if (p.thread != null) ++n; } return n; }
获取队列中所有线程
1
2
3
4
5
6
7
8
9
10public final Collection<Thread> getQueuedThreads() { ArrayList<Thread> list = new ArrayList<Thread>(); for (Node p = tail; p != null; p = p.prev) { Thread t = p.thread; if (t != null) list.add(t); } return list; }
描述线程状态
1
2
3
4
5
6
7public String toString() { Thread o = sync.getOwner(); return super.toString() + ((o == null) ? "[Unlocked]" : "[Locked by thread " + o.getName() + "]"); }
创建一个条件
1
2
3
4
5
6
7public Condition newCondition() { return sync.newCondition(); } final ConditionObject newCondition() { return new ConditionObject(); }
最后
以上就是年轻煎蛋最近收集整理的关于详解ReentrantLock---公平锁与非公平锁的全部内容,更多相关详解ReentrantLock---公平锁与非公平锁内容请搜索靠谱客的其他文章。
发表评论 取消回复