introduction to computer science and programming in java concurrency issues.pdf · outline...
Post on 22-Mar-2020
21 Views
Preview:
TRANSCRIPT
Concurrency
Fundamentals of Computer Science
http://csunplugged.org/routing-and-deadlock
Outline
Multi-threaded programs
Multiple simultaneous paths of execution
Seemingly at once (single core)
Actually at the same time (multiple cores)
Concurrency issues
The dark side of threading
Unpredictability of thread scheduler
Protecting shared data:
synchronized methods
Deadlock
The really dark side of threading
public class BlastOff implements Runnable { public void run() { for (int i = 10; i > 0; i--) System.out.print(i + " "); System.out.println("BLAST OFF!"); } }
public class Launch { public static void main(String [] args) { System.out.println("prepare for launch"); Thread thread = new Thread(new BlastOff()); thread.start(); System.out.println("done with launch"); } }
% java Launch prepare for launch done with launch 10 9 8 7 6 5 4 3 2 1 BLAST OFF!
Review: Creating & Starting a Thread
% java Launch prepare for launch 10 9 done with launch 8 7 6 5 4 3 2 1 BLAST OFF!
% java Launch prepare for launch 10 done with launch 9 8 7 6 5 4 3 2 1 BLAST OFF!
…
% java ParallelSearch 1000000 2 7 16 42 99 Starting workers... Count of 2 = 9888 Count of 7 = 10222 Count of 16 = 9989 Count of 42 = 10099 Count of 99 = 9894
Review: Multithreading for Speed
Goal: Count how often different integers occur
In a large array of integers
Randomly generated in [0, 100)
Have one thread handle each target integer
public class SearchWorker implements Runnable { private int target = 0; private int [] data = null; private int result = 0;
public SearchWorker(int target, int [] data) { this.target = target; this.data = data; }
public int getResult() { return result; }
public int getTarget() { return target; }
public void run() { for (int i = 0; i < data.length; i++) { if (data[i] == target) result++; } } }
Worker object: One of these is created for each target integer we want to search for.
Needs to keep track of its input: what number to search for, the array to search in.
Must remember its output: count of the target in the array.
... final int DATA_SIZE = Integer.parseInt(args[0]); final int WORKERS = args.length - 1;
int [] data = new int[DATA_SIZE]; for (int i = 0; i < DATA_SIZE; i++) data[i] = (int) (Math.random() * 100);
SearchWorker [] workers = new SearchWorker[WORKERS]; Thread [] threads = new Thread[WORKERS];
for (int i = 0; i < WORKERS; i++) { workers[i] = new SearchWorker(Integer.parseInt(args[i + 1]), data); threads[i] = new Thread(workers[i]); threads[i].start(); }
for (int i = 0; i < WORKERS; i++) { try { threads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Count of %d = %d\n", workers[i].getTarget(), workers[i].getResult()); } ...
Client program: 1. Parses command line arguments. 2. Creates random array of data to search
in. 3. Creates each worker, launches each
worker in its own thread. 4. Waits for each thread to finish, printing
out the worker’s result.
Trouble in Concurrency City: Act 1
Lost update problem Multiple threads
All sharing a single counter object
Each thread increments fixed number of times
public class Count { private int count = 0; public int getCount() { return count; } public void increment() { count++; } }
public class IncrementWorker implements Runnable { private Count count = null; public IncrementWorker(Count count) { this.count = count; } public void run() { for (int i = 0; i < 1000; i++) count.increment(); } }
Lost Update Problem
... Count count = new Count(); Thread [] threads = new Thread[N]; for (int i = 0; i < N; i++) { threads[i] = new Thread(new IncrementWorker(count)); threads[i].start(); } for (int i = 0; i < N; i++) { try { threads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Final count = " + count.getCount()); ...
% java Increment 1 Final count = 1000 % java Increment 2 Final count = 2000 % java Increment 20 Final count = 20000 % java Increment 20 Final count = 19761 % java Increment 20 Final count = 19014
Synchronizing Methods
Only allow 1 worker in increment at a time!
Tell Java this using synchronized keyword
public class Count { private int count = 0; public int getCount() { return count; } public synchronized void increment() { count++; } }
% java Increment 20 Final count = 20000 % java Increment 20 Final count = 20000 % java Increment 20 Final count = 20000
Locking an Object
Each object instance has a lock
Multiple methods can be marked synchronized
Only one can be executing at any time
Locking is on the object level
On the instance of the class, not the class data type itself
Locking and unlocking takes time
Only synchronize methods if necessary
public void run() { for (int i = 0; i < 1000; i++) { synchronized (count) { count.increment(); } } }
Another approach to fixing the lost update problem.
Synchronization can be enforced on a block of code instead of an entire method.
Trouble in Concurrency City: Act 2
Concurrent access to same data structure
Many built-in containers are not thread-safe!
e.g. ArrayList, HashMap
Program will crash (probably)
Protect all reading/writing to shared structure
Via synchronized method or synchronized code block
public class ArrayListBad implements Runnable { private static ArrayList<Integer> list = new ArrayList<Integer>();
public void run() { for (int i = 0; i < 10; i++) { list.add((int) (Math.random() * 100)); } System.out.println("Thread all done..."); }
public static void main(String[] args) { Thread t1 = new Thread(new ArrayListBad()); t1.start();
Thread t2 = new Thread(new ArrayListBad()); t2.start();
try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Phew, we made it!"); } } 12
May sometimes work, especially if loop in run() is short.
But most likely you’ll get some sort of exception: Exception in thread "Thread-1" Thread all done... java.lang.ArrayIndexOutOfBoundsException: 15 at java.util.ArrayList.add(Unknown Source) at ArrayListBad.run(ArrayListBad.java:12) at java.lang.Thread.run(Unknown Source) Phew, we made it!
public class ArrayListGood implements Runnable { private static ArrayList<Integer> list = new ArrayList<Integer>(); public void run() { for (int i = 0; i < 100000; i++) { synchronized(list) { list.add((int) (Math.random() * 100)); } } System.out.println("Thread all done..."); } ...
13
Adding synchronized block protects the shared static list instance variable, now only one thread is allowed to add to the list at any point in time.
Trouble in Concurrency City: Act 3
Deadlock Program stops doing anything useful
All you need is 2 objects and 2 threads
Summary
Multi-threaded programs
Multiple simultaneous paths of execution
Seemingly at once (single core)
Actually at the same time (multiple cores)
Concurrency issues
The dark side of threading
Unpredictability of thread scheduler
Protecting shared data:
synchronized methods
Deadlock
The really dark side of threading
Your Turn
Goal: Increment/decrement all ints in an array Create class NumHolder that implements Runnable, holds array of 100 ints
Create increment() and decrement() methods Methods that go through all 100 integers and ++ or -- them
Create run() method Loop 1000 times, each loop flip coin and call either increment() or decrement()
Create main program in NumHolderLaunch Create a single NumHolder object Create two threads, passing them the NumHolder object you created Print out NumHolder object Start threads, wait for them to finish Print out NumHolder again
Hint: All numbers should be the same in the second print of NumHolder
Open Moodle, go to CSCI 136, Section 01 Open the dropbox Activity 7 - Concurrency Drag and drop your program file to the Moodle dropbox You get: 1 point if you turn in something, 2 points if you turn in
something that is correct.
top related