Presentation is loading. Please wait.

Presentation is loading. Please wait.

Ken Wadland, PhD Refactoring to Concurrency (Java Edition) Prepared for: Boston Java Meetup Group February 2011.

Similar presentations


Presentation on theme: "Ken Wadland, PhD Refactoring to Concurrency (Java Edition) Prepared for: Boston Java Meetup Group February 2011."— Presentation transcript:

1 Ken Wadland, PhD Refactoring to Concurrency (Java Edition) Prepared for: Boston Java Meetup Group February 2011

2 Overview Step 1: Establish Performance Criteria Step 2: Annotate Existing Class Thread Safety Step 3: Increase Thread Safety (as needed) Step 4: Use Tasks instead of loops/steps Step 5: Use Thread Pool Step 6: Increase Concurrency Copyright 2010, Concurrency Magic

3 Common Concurrency Problems Data Race Condition Deadlock Liveliness Memory Visibility And, Heisenbugs Copyright 2010, Concurrency Magic

4 Example Problem Solving Sudoku Puzzles

5 Single Threaded Sudoku (4x4 There are 12 Houses – 4 Rows – 4 Columns – 4 Boxes Each Value (1 - 4) must appear exactly once in each House Algorithm: – Look for Singles – (Cells where only one value is valid) 3 4 13 2 2 4 1 1 31 2 2 4 43

6 Concurrent Sudoku: Thread per value * * 1* * * ** 3 * *3 * 4 ** XX XX XX X X X X XX X X XX X X XX X X 1 X 3 X X 2 3 4 2 X X X XX X 4 X 4 X 2 X 2 X 1 X 1 Thread Algorithm: 4 Threads. Each c onsiders one value Mark which cells cannot have that value Look for Singles for that value

7 Alternative Algorithm #1: Thread per cell 3 4 13 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 Thread Algorithm: 16 threads each consider one c ell and its 4 candidates Look at neighbor cells in 3 houses Remove invalid candidates

8 Alternative Alogorithm #2: Thread per House 3 4 13 3 4 13 3 4 13 4 4 2 2 2 2 2 4 2 4 4 4 2 2 2 3 1 3 3 1 1 4 4 4 3 1 3 3 1 1 2 2 2 1 1 1

9 Alternative Algorithm #3: Thread per Candidate 3 4 13 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 1 3 2 4 Thread Algorithm: 64 Threads. Each c onsider s one candidate Look at neighbor cells in 3 houses Remove if invalid

10 Package Architecture Copyright 2010, Concurrency Magic

11 Step 1: Establish Criteria If you dont know where youre going, how will you know when you gotten there?

12 Success Criteria Examples Good Examples: – Response time < 1ms for typical queries – Process >100 queries per second – Deterministic Results Bad Examples: – Keep all processors busy – Keep all threads busy – Avoid waiting for locks Copyright 2010, Concurrency Magic

13 Performance Test Copyright 2010, Concurrency Magic

14 Timing Java Apps (1 st attempt) Start timer Run algorithm A Stop timer Report elapsed time Start timer Run algorithm B Stop timer Report elapsed time... Start timer Run algorithm Z Stop timer Report elapsed time Copyright 2010, Concurrency Magic

15 Timing Java Apps (2 nd attempt) Repeat 1000 times Start timer Repeat 100 times (with 100 different puzzles) Run algorithm A Stop timer Report min/ave/max times (divided by 100,000) Repeat 1000 times Start timer Repeat 100 times (with 100 different puzzles) Run algorithm B Stop timer Report min/ave/max times (divided by 100,000)... Copyright 2010, Concurrency Magic

16 Timing Java Apps (3 rd attempt) Repeat 1000 times Start timer A Repeat 100 times: Run algorithm A Stop timer A Start timer B Repeat 100 times: Run algorithm B Stop timer B... Start timer Z Repeat 100 times: Run algorithm Z Stop timer Z Report min/ave/max (divided by 100,000) Copyright 2010, Concurrency Magic

17 Timing Java Apps (4 th attempt) Start JVM Repeat 1000 times Start timer Repeat 100 times (with 100 different puzzles) Run algorithm A Stop timer Report min/ave/max times (divided by 100,000) Stop JVM Repeat for each algorithm Copyright 2010, Concurrency Magic

18 Statistics Gathering Performance results solving 100 puzzles 1000 times. Sample Goal: cut time in half using 4 cores Best TimeAve TimeNicknameAlgorithm 15.261 ms16.456 msSTPPencil 30.569 ms32.806 msSTSScanner

19 Step 2: Annotate Type Safety Assign Type Safety Annotation to every class that might be used concurrently

20 Concurrency Categories for Classes Immutable Thread-Safe Thread-Friendly Thread-Neutral Thread-Hostile Copyright 2010, Concurrency Magic

21 New Package: Annotations public @interface Immutable { } public @interface ThreadSafe { } public @interface ThreadFriendly { } public @interface ThreadHostile { } public @interface ThreadNeutral { } public @interface GuardedBy { String value(); }

22 Copyright 2010, Concurrency Magic Value public enum Value { UNKNOWN(0, '.'), ONE(1, '1'), TWO2, '2'),... FIFTEEN (15, 'F'), SIXTEEN (16, 'G'); final private int number; final private char name; final static private Map charMap = new HashMap (); final static private List intList = new ArrayList (16);... @Immutable

23 Copyright 2010, Concurrency Magic Location public class Location { private int row; private int col; private int offset; private int boxSize;... @ThreadNeutral

24 Copyright 2010, Concurrency Magic ValueSet public class ValueSet { private Value value = Value.UNKNOWN; private EnumSet includedValues;... @ThreadNeutral

25 Copyright 2010, Concurrency Magic Puzzle public class Puzzle implements Cloneable { public static final List SUPPORTED_SIZES = Arrays.asList(4, 9, 16); static int size = 0; static int boxSize = 0; static int gridSize = 0; private static List > rows; private static List > cols; private static List > boxes; private static List > houses; private static List allLocations; private List values;... @ThreadHostile

26 Step 3: Increase Thread Safety (as needed) Modify classes or create new classes with higher levels of atomicity Copyright 2010, Concurrency Magic

27 Concurrency in Java Copyright 2010, Concurrency Magic AbstractQueuedSynchronizer Your Thread Safe Code java.util.concurrent.lock compareAndSwap, AtomicReference java.util.concurrent.atomic happens before Java JVM Lock (ReentrantLock), Condition java.util.concurrent.lock CountDownLatch, Semaphore java.util.concurrent AtomicInteger, AtomicLongArray java.util.concurrent.atomic Executer, Future, ConcurrentMap java.util.concurrent Your Thread Neutral Code

28 Copyright 2010, Concurrency Magic Location final public class Location { final private int row; final private int col; final private int offset; final private int boxSize; // Getters but not Setters

29 Copyright 2010, Concurrency Magic Puzzle Hierarchy

30 Copyright 2010, Concurrency Magic Puzzle (Base Class) public abstract class Puzzle implements Cloneable { /** List of Puzzle sizes supported (4x4, 9x9 and 16x16). */ public static final List SUPPORTED_SIZES = Arrays.asList(4, 9, 16); /** Puzzle table used when this Puzzle was created. */ protected final PuzzleTables tables; /** Size of this Puzzle (4, 9 or 16). */ protected final int size;

31 Copyright 2010, Concurrency Magic Basic Puzzle (Thread Neutral) @ThreadNeutral public final class BasicPuzzle extends Puzzle { /** Table containing current Values for each cell in grid. */ private final List values;

32 Copyright 2010, Concurrency Magic BasicPuzzle get/set @Override public Value getValue (Location loc) { return values.get(loc.getOffset()); } @Override public void setValue (Location loc, Value v) { values.set(loc.getOffset(), v); }

33 Copyright 2010, Concurrency Magic SynchronizedPuzzle @ThreadSafe public class SynchronizedPuzzle extends Puzzle { @GuardedBy("this") private final List values; @Override public synchronized Value getValue (Location loc) { return values.get(loc.getOffset()); } @Override public synchronized void setValue (Location loc, Value v) { values.set(loc.getOffset(), v); }

34 Copyright 2010, Concurrency Magic LockingPuzzle.LockableValue @ThreadSafe public final class LockingPuzzle extends Puzzle { /** Value that can be locked */ private class LockableValue { private Value value; public LockableValue() { value = Value.UNKNOWN;} public synchronized Value get() { return value; } public synchronized void set(Value v) { value = v; } }

35 Copyright 2010, Concurrency Magic LockingPuzzle get/set @GuardedBy("itself") private final List values; @Override public Value getValue (Location loc) { return values.get(loc.getOffset()).get(); } @Override public void setValue (Location loc, Value v) { values.get(loc.getOffset()).set(v); }

36 Copyright 2010, Concurrency Magic AtomicPuzzle @ThreadSafe public final class AtomicPuzzle extends Puzzle { AtomicReferenceArray values; @Override public Value getValue (Location loc) { return values.get(loc.getOffset()); } @Override public void setValue (Location loc, Value v) { values.set(loc.getOffset(), v); }...

37 Copyright 2010, Concurrency Magic ImmutablePuzzle @Immutable public final class ImmutablePuzzle extends Puzzle { private final List values; @Override public Value getValue (Location loc) { return values.get(loc.getOffset()); } @Override public void setValue (Location loc, Value v) { throw new IllegalArgumentException( "setValue is not implemented for ImmutablePuzzle"); }

38 New class: GenericScanSolver public class ScanSolver extends Solver { /** Puzzle currently being solved. */ final BasicPuzzle puzzle;... public class GenericScanSolver extends Solver { /** Puzzle currently being solved. */ final Puzzle puzzle;... Copyright 2010, Concurrency Magic

39 Use SynchronizedPuzzle ST_SCANNER_WTH_SYNCHRONIZED_PUZZLE("STS.S") { public String getName() { return "ST Scanner with SynchronizedPuzzle"; } public Solver newSolver(Puzzle input, Verbosity verbosity) { Puzzle p = SynchronizedPuzzle.makeCopy(input); Solver s = GenericScanSolver.newSolver(p, verbosity); return s; } }, Copyright 2010, Concurrency Magic

40 Use LockingPuzzle ST_SCANNER_WTH_LOCKING_PUZZLE("STS.L") { public String getName() { return "ST Scanner with LockingPuzzle"; } public Solver newSolver(Puzzle input, Verbosity verbosity) { Puzzle p = LockingPuzzle.makeCopy(input); Solver s = GenericScanSolver.newSolver(p, verbosity); return s; } }, Copyright 2010, Concurrency Magic

41 Step 4: Use Tasks Convert loops and/or separate steps into Tasks. Execute Tasks from a Queue. (Still Single Threaded) Copyright 2010, Concurrency Magic

42 Creating Executor private boolean runAllTests() { // Create pool of threads to execute tasks ExecutorService exec = Executors.newSingleThreadExecutor(); try { for (PuzzleResults r : results) { if (runOneTest(exec, r) != true) { // Report error return false; } } finally { exec.shutdown(); } return true; } Copyright 2010, Concurrency Magic

43 Pass (unused) Executor public static Solver newSolver(Executor exec, Puzzle input, Verbosity verbosity) { return new ScanSolver(input, verbosity); }

44 Using Tasks in seekHiddenSingles protected void seekHiddenSingles() { final CountDownLatch latch = new CountDownLatch(unsolvedValues.count()); for (final Value v : unsolvedValues.getAllValues()) { Runnable task = new Runnable() { public void run() { boolean foundAll = seekOneHiddenSingle(v); if (foundAll) { unsolvedValues.removeValue(v); } latch.countDown(); } }; exec.execute(task); } try { latch.await();... Error handling } Copyright 2010, Concurrency Magic

45 Step 5: Use a Thread Pool Replace Single Threaded Executor with Multi-threaded Executor Copyright 2010, Concurrency Magic

46 Creating Thread Pool private boolean runAllTests() { // Create pool of threads to execute tasks ExecutorService exec = Executors.newFixedThreadPool(numberOfThreads); try { for (PuzzleResults r : results) { if (runOneTest(exec, r) != true) { // Report error return false; } } finally { exec.shutdown(); } return true; } Copyright 2010, Concurrency Magic

47 Step 6: Increase Concurrency In this case, rather than solve one Puzzle in parallel, solve different Puzzles in parallel Copyright 2010, Concurrency Magic

48 Concurrent Sudoku #5: Thread per puzzle 3 4 13 4 1 1 2 1 2 23 3 4 2 3 4 4 1 2 2 4 1 32 2 2 3 1 1 1 4 4 4 4 3 4 3 1 2 1 4 33 3 1 2 2

49 Task to Solve one Puzzle class PuzzleSolver implements Callable { private final SolverType solverType; private final PuzzleInfo info; public PuzzleSolver (SolverType s, PuzzleInfo info) { … } public Solvability call () { … } } Copyright 2010, Concurrency Magic

50 Submit Tasks to Executor protected boolean solveOneSetOfPuzzles(SolverType s) { ExecutorService exec = Executors.newSingleThreadExecutor(); for (PuzzleInfo info : puzzles) { Callable task = new PuzzleSolver(s, info); exec.submit(task); } exec.shutdown(); // Error handling } Copyright 2010, Concurrency Magic

51 Use a Thread Pool protected boolean solveOneSetOfPuzzles(SolverType s) { // ExecutorService exec = // Executors.newSingleThreadExecutor(); ExecutorService exec = Executors.newFixedThreadPool(numberOfThreads); Copyright 2010, Concurrency Magic

52 Summary Step 1: Establish Performance Criteria Step 2: Annotate Existing Class Thread Safety Step 3: Increase Thread Safety (as needed) Step 4: Use Tasks instead of loops/steps Step 5: Use Thread Pool Step 6: Increase Concurrency Copyright 2010, Concurrency Magic


Download ppt "Ken Wadland, PhD Refactoring to Concurrency (Java Edition) Prepared for: Boston Java Meetup Group February 2011."

Similar presentations


Ads by Google