一、介绍
Object的监视器方法
在使用synchronized获取到锁的前提下,通过Object的wait、notify、notifyAll可以在多线程场景下做到并发控制
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
| public void testWaitNotify() throws InterruptedException { Object object1 = new Object(); Thread thread1 = new Thread(() -> { while (true) { try { Thread.sleep(500); } catch (InterruptedException e) { throw new RuntimeException(e); } synchronized (object1) { System.out.println("线程1打印信息"); object1.notify(); } } }); Thread thread2 = new Thread(() -> { while (true) { synchronized (object1){ try { object1.wait(); System.out.println("线程2打印信息"); } catch (InterruptedException e) { throw new RuntimeException(e); } } } });
thread1.start(); thread2.start(); }
|
Condition的使用
相对于Object的监视器方法,在Lock获取到锁的前提下,可以用await、signal、signalAll可以替代Object的那套监视器方法,并且更加灵活更加好控制。
因为方法到共享状态信息发生在不同的线程中,需要对其进行保护,所以需要锁来进行保护。
基本使用方法:
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
| public void testAwaitSignal() throws InterruptedException { ReentrantLock reentrantLock=new ReentrantLock(); Condition condition= reentrantLock.newCondition(); Thread thread1 = new Thread(() -> { while (true) { try { Thread.sleep(1500); reentrantLock.lock(); System.out.println("线程1打印信息"); condition.signal(); } catch (InterruptedException e) { throw new RuntimeException(e); }finally { reentrantLock.unlock(); } } }); Thread thread2 = new Thread(() -> { while (true) { try { reentrantLock.lock(); condition.await(); System.out.println("线程2打印信息"); } catch (InterruptedException e) { throw new RuntimeException(e); }finally { condition.signal(); } } });
thread1.start(); thread2.start(); }
|
ConditionObject数据结构
1 2 3 4 5 6 7
| public class ConditionObject implements Condition, java.io.Serializable { private transient Node firstWaiter;
private transient Node lastWaiter; }
|
二、await源码
简图:部分逻辑(不包含打断之类的判断)
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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
| public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); int interruptMode = 0; while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); }
private Node addConditionWaiter() { Node t = lastWaiter; if (t != null && t.waitStatus != Node.CONDITION) { unlinkCancelledWaiters(); t = lastWaiter; } Node node = new Node(Thread.currentThread(), Node.CONDITION); if (t == null) firstWaiter = node; else t.nextWaiter = node; lastWaiter = node; return node; }
private void unlinkCancelledWaiters() { Node t = firstWaiter; Node trail = null; while (t != null) { Node next = t.nextWaiter; if (t.waitStatus != Node.CONDITION) { t.nextWaiter = null; if (trail == null) firstWaiter = next; else trail.nextWaiter = next; if (next == null) lastWaiter = trail; } else trail = t; t = next; } }
final int fullyRelease(Node node) { boolean failed = true; try { int savedState = getState(); if (release(savedState)) { failed = false; return savedState; } else { throw new IllegalMonitorStateException(); } } finally { if (failed) node.waitStatus = Node.CANCELLED; } }
final boolean isOnSyncQueue(Node node) { if (node.waitStatus == Node.CONDITION || node.prev == null) return false; if (node.next != null) return true; return findNodeFromTail(node); } private int checkInterruptWhileWaiting(Node node) { return Thread.interrupted() ? (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0; }
private boolean findNodeFromTail(Node node) { Node t = tail; for (; ; ) { if (t == node) return true; if (t == null) return false; t = t.prev; } }
final boolean transferAfterCancelledWait(Node node) { if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { enq(node); return true; }
while (!isOnSyncQueue(node)) Thread.yield(); return false; }
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; failed = false; return interrupted; }
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
|
三、signal
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
|
public final void signal() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignal(first); }
private void doSignal(Node first) { do { if ((firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; } while (!transferForSignal(first) && (first = firstWaiter) != null); }
final boolean transferForSignal(Node node) { if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; Node p = enq(node); int ws = p.waitStatus; if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; }
|
四、signalAll
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public final void signalAll() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignalAll(first); }
private void doSignalAll(Node first) { lastWaiter = firstWaiter = null; do { Node next = first.nextWaiter; first.nextWaiter = null; transferForSignal(first); first = next; } while (first != null); }
|