深入浅出 java concurrency
Embed Size (px)
TRANSCRIPT
Java Concurrency (1) : J.U.CGuice Guice java.util.concurrent(J.U.C) Java Java Java
1 2
J.U.C J.U.C
API
3
J.U.C
J.U.C
J.U.C MindManger
API MindManger 8
J.U.C
MindManger API
Java Concurrency (2):Atomic Atomic java.util.concurrent
part 1Queue Queue
Java +1/-1 - Doug Lea
++i
--i
JSR 166 Java
backport-util-concurrent synchronized
public final synchronized void set(int newValue); public final synchronized int getAndSet(int newValue); public final synchronized int incrementAndGet(); volatile synchronized volatile JNI get() Java
JSR 166 CPU API
backport-util-concurrent
JDK 5.0
java.util.concurrent.atomic.AtomicInteger int addAndGet(int delta) i =i+delta boolean compareAndSet(int expect, int update) == false true
int decrementAndGet() 1 int get() --i
int getAndAdd(int delta) t=i;i+=delta;return t; int getAndDecrement() 1 int getAndIncrement() 1 int getAndSet(int newValue) t=i;i=newValue;return t; int incrementAndGet() 1 void lazySet(int newValue) set() volatile volatile ++i i++ i--
void set(int newValue) i=newValue boolean weakCompareAndSet(int expect, int update) == happen-before weakCompareAndSet weakCompareAndSet Java compareAndSet happen-before JSR unsafe.compareAndSwapInt() JSR
package xylz.study.concurrency.atomic; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; importstatic org.junit.Assert.*; publicclass AtomicIntegerTest { @Test publicvoid testAll() throws InterruptedException{ final AtomicInteger value = new AtomicInteger(10); assertEquals(value.compareAndSet(1, 2), false); assertEquals(value.get(), 10); assertTrue(value.compareAndSet(10, 3)); assertEquals(value.get(), 3); value.set(0); // assertEquals(value.incrementAndGet(), 1); assertEquals(value.getAndAdd(2),1); assertEquals(value.getAndSet(5),3); assertEquals(value.get(),5); // finalint threadSize = 10; Thread[] ts = new Thread[threadSize]; for (int i = 0; i < threadSize; i++) { ts[i] = new Thread() { publicvoid run() { value.incrementAndGet(); } }; } // for(Thread t:ts) {
t.start(); } for(Thread t:ts) { t.join(); } // assertEquals(value.get(), 5+threadSize); } }
AtomicInteger
AtomicLong AtomicBoolean AtomicReference
(1)http://stackoverflow.com/questions/2443239/java-atomicinteger-what-are-thedifferences-between-compareandset-and-weakcompar (2)http://stackoverflow.com/questions/1468007/atomicinteger-lazyset-and-set
Java Concurrency (3):
part 2
AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray AtomicIntegerArray int get(int i) i IndexOutOfBoundsException API AtomicInteger
API
void set(int i, int newValue) void lazySet(int i, int newValue) int getAndSet(int i, int newValue) boolean compareAndSet(int i, int expect, int update) boolean weakCompareAndSet(int i, int expect, int update) int getAndIncrement(int i) int getAndDecrement(int i) int getAndAdd(int i, int delta) int incrementAndGet(int i) int decrementAndGet(int i) int addAndGet(int i, int delta) API
AtomicIntegerFieldUpdater/AtomicLongFieldUpdater/AtomicRef erenceFieldUpdater API 1 volatile volatile volatile
2
public/protected/default/private
3 4 volatile 5 int/long AtomicReferenceFieldUpdater AtomicIntegerFieldUpdater final final
static final
AtomicLongFieldUpdater
Integer/Long
package xylz.study.concurrency.atomic; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; publicclass AtomicIntegerFieldUpdaterDemo { class DemoData{ publicvolatileint value1 = 1; volatileint value2 = 2; protectedvolatileint value3 = 3; privatevolatileint value4 = 4; } AtomicIntegerFieldUpdater getUpdater(String fieldName) { return AtomicIntegerFieldUpdater.newUpdater(DemoData.class, fieldName); } void doit() { DemoData data = new DemoData(); System.out.println("1 ==> "+getUpdater("value1").getAndSet(data, 10)); System.out.println("3 ==> "+getUpdater("value2").incrementAndGet(data)); System.out.println("2 ==> "+getUpdater("value3").decrementAndGet(data)); System.out.println("true ==> "+getUpdater("value4").compareAndSet(data, 4, 5)); } publicstaticvoid main(String[] args) {
AtomicIntegerFieldUpdaterDemo demo = new AtomicIntegerFieldUpdaterDemo(); demo.doit(); } }
DemoData
value3/value4
AtomicIntegerFieldUpdaterDemo
AtomicMarkableReference Object Boolean Object/Boolean AtomicStampedReference AtomicMarkableReference AtomicStampedReference
AtomicInteger Object ABA ABA
AtomicMarkableReference/AtomicStampedReference
Java Concurrency (4): happens-before
part 3
Java Concurrency in Practice
Java
JVM
JVM CPU
CPU
CPU
CPU
package xylz.study.concurrency.atomic; publicclass ReorderingDemo { staticint x = 0, y = 0, a = 0, b = 0; publicstaticvoid main(String[] args) throws Exception {
for (int i = 0; i < 100; i++) { x=y=a=b=0; Thread one = new Thread() { publicvoid run() { a = 1; x = b; } }; Thread two = new Thread() { publicvoid run() { b = 1; y = a; } }; one.start(); two.start(); one.join(); two.join(); System.out.println(x + " " + y); } } }
one/two 1) 10 11 00 run()
x,y,a,b JVM run() 0,0 CPU
100 00 CPU JVM
(0
a=1;x=b;b=1;y=a; x=0 1 a 0 a=1 y=a one one a=1 two
CPU
Happens-beforeJava A/B happens-before Action Java start() join() Action happens-before A/B JMM B happens-before Java Memeory Model A
happens-before 1 2 3 volatile Action happens-before Action
happens-before happens-before happens-before happens-before Thread.isAlive()==false A A B A B B interrupt isInterrupted happens-before interrupted() finalizer B happens-before C A
4 Thread.start() 5 Thread Thread.join 6 B 7 8 A A
happens-before happens-before C B
happens-before
volatilevolatile volatile synchronized volatile volatile volatile volatile synchronized
1
Java
valatile
volatile
2 volatile volatile volatile happens-before valatile volatile volatile volatile
CPU
volatile
volatile volatileboolean done = false; while( ! done ){ dosomething(); } volatile 1 2 3
1 2
Java Concurrency in Practice Volatile
Java Concurrency (5):JDK 5 Java synchronized
part 4
1 2 3
volatile
volatile
synchronized
CASCAS CAS V 3 V B V Compare and Swap A B A
nonblocking algorithms
CPU compareAndSet() AtomicInteger private volatile int value; volatile
public final int get() { return value; } ++i public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } } CAS +1 CAS
compareAndSet
JNI
CPU
public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } CPU CAS JNI Java
J.U.C
CAS
synchronized CAS
J.U.C
CAS CAS
ABA
one two CAS A B
V two one
A V one
two A CAS one
A
AtomicStampedReference/AtomicMarkableReference
1 2
Java Concurrency (6):
part 1
synchronized JDK 5 JDK 5
JDK 5 JNI
java.util.concurrent.locks.Lock
java.util.concurrent.locks.ReadWriteLock java.util.concurrent.locks.Lock void lock(); API
void lockInterruptibly() throws InterruptedException;
y y
y y InterruptedException Condition newCondition();
Lock
Condition
Condition
boolean tryLock();
true
false
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
true
y y
y true
y y InterruptedException false time 0
void unlock(); lock() tryLock() tryLock(xx) lockInterruptibly() unlock() API AtomicInteger
package xylz.study.concurrency.lock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class AtomicIntegerWithLock { private int value; private Lock lock = new ReentrantLock(); public AtomicIntegerWithLock() { super(); } public AtomicIntegerWithLock(int value) { this.value = value; } public final int get() { lock.lock(); try { return value; } finally { lock.unlock(); } } public final void set(int newValue) { lock.lock(); try { value = newValue; } finally { lock.unlock(); } } public final int getAndSet(int newValue) { lock.lock(); try {
int ret = value; value = newValue; return ret; } finally { lock.unlock(); } } public final boolean compareAndSet(int expect, int update) { lock.lock(); try { if (value == expect) { value = update; return true; } return false; } finally { lock.unlock(); } } public final int getAndIncrement() { lock.lock(); try { return value++; } finally { lock.unlock(); } } public final int getAndDecrement() { lock.lock(); try { return value--; } finally { lock.unlock();
} } public final int incrementAndGet() { lock.lock(); try { return ++value; } finally { lock.unlock(); } } public final int decrementAndGet() { lock.lock(); try { return --value; } finally { lock.unlock(); } } public String toString() { return Integer.toString(get()); } } AtomicIntegerWithLock lock/unlock Lock lock() unlock lock() unlock() finally unlock Lock ++/--
java.util.concurrent.locks.ReentrantLock.ReentrantLock Lock synchronized Lock Lock
public static void main(String[] args) throws Exception{ final int max = 10; final int loopCount = 100000; long costTime = 0; for (int m = 0; m < max; m++) { long start1 = System.nanoTime(); final AtomicIntegerWithLock value1 = new AtomicIntegerWithLock(0); Thread[] ts = new Thread[max]; for(int i=0;i0 CANCELLED waitStatus 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus = 0) { setHeadAndPropagate(node, r); p.next = null; // help GC return; } } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) break; } } catch (RuntimeException ex) { cancelAcquire(node); throw ex; } // Arrive here only if interrupted cancelAcquire(node); throw new InterruptedException(); } await
1. 2. 0 3 3. unpark 4. 2 3
AQS
CLH 2
(park) 2
setHeadAndPropagate tryAcquireShared propagate>=0 1 -1 setHeadAndPropagate
propagate==1
private void setHeadAndPropagate(Node node, int propagate) { setHead(node); if (propagate > 0 && node.waitStatus != 0) { Node s = node.next; if (s == null || s.isShared()) unparkSuccessor(node); } } countDown FIFO CountDownLatch releaseShared(1) tryReleaseShared CAS -1 countDown AQS 0
public boolean tryReleaseShared(int releases) { for (;;) { int c = getState(); if (c == 0) return false; int nextc = c-1; if (compareAndSetState(c, nextc)) return nextc == 0; } } CountDownLatch CountDownLatch AQS
Java Concurrency (11):CountDownLatch
part 6 CyclicBarrierCyclicBarrier
(common barrier point)
1
CyclicBarrier
package xylz.study.concurrency.lock; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class CyclicBarrierDemo { final CyclicBarrier barrier; final int MAX_TASK; public CyclicBarrierDemo(int cnt) { barrier = new CyclicBarrier(cnt + 1); MAX_TASK = cnt; } public void doWork(final Runnable work) { new Thread() { public void run() { work.run(); try { int index = barrier.await(); doWithIndex(index); } catch (InterruptedException e) { return; } catch (BrokenBarrierException e) { return; } } }.start(); }
private void doWithIndex(int index) { if (index == MAX_TASK / 3) { System.out.println("Left 30%."); } else if (index == MAX_TASK / 2) { System.out.println("Left 50%"); } else if (index == 0) { System.out.println("run over"); } } public void waitForNext() { try { doWithIndex(barrier.await()); } catch (InterruptedException e) { return; } catch (BrokenBarrierException e) { return; } } public static void main(String[] args) { final int count = 10; CyclicBarrierDemo demo = new CyclicBarrierDemo(count); for (int i = 0; i < 100; i++) { demo.doWork(new Runnable() { public void run() { //do something try { Thread.sleep(1000L); } catch (Exception e) { return; } } }); if ((i + 1) % count == 0) { demo.waitForNext();
} } } } 1 10 50% 30% CyclicBarrierDemo count+1 100
50% 30% CyclicBarrier
0
y
await() await() -1 parties-1, cnt+1 CyclicBarrier 1 0 parties
y
y
CyclicBarrier
y 1 50% 30% 0% cnt+1 CyclicBarrier 0% y CyclicBarrier await InterruptedException y await() CyclicBarrier await()==0
y
CyclicBarrier
API public CyclicBarrier(int parties) CyclicBarrier barrier public CyclicBarrier(int parties, Runnable barrierAction) barrier barrier y public int await() throws InterruptedException, BrokenBarrierException barrier y await public int await(long timeout,TimeUnit unit) throws InterruptedException, BrokenBarrierException,TimeoutException await , y public int getNumberWaiting() public int getParties() public boolean isBroken() public void reset() API barrier CyclicBarrier
y
y
y
y
y API
CyclicBarrier
2 CyclicBarrier.await*() private int dowait(boolean timed, long nanos) throws InterruptedException, BrokenBarrierException, TimeoutException { final ReentrantLock lock = this.lock; lock.lock(); try { final Generation g = generation;
if (g.broken) throw new BrokenBarrierException(); if (Thread.interrupted()) { breakBarrier(); throw new InterruptedException(); } int index = --count; if (index == 0) { // tripped boolean ranAction = false; try { final Runnable command = barrierCommand; if (command != null) command.run(); ranAction = true; nextGeneration(); return 0; } finally { if (!ranAction) breakBarrier(); } } // loop until tripped, broken, interrupted, or timed out for (;;) { try { if (!timed) trip.await(); else if (nanos > 0L) nanos = trip.awaitNanos(nanos); } catch (InterruptedException ie) { if (g == generation && ! g.broken) { breakBarrier(); throw ie; } else { Thread.currentThread().interrupt();
} } if (g.broken) throw new BrokenBarrierException(); if (g != generation) return index; if (timed && nanos