深入浅出 Java Concurrency

download 深入浅出 Java Concurrency

If you can't read please download the document

Transcript of 深入浅出 Java Concurrency

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