1 / 26

Component-Based Software Engineering

Component-Based Software Engineering. Understanding Thread Safety Paul Krause. Lecture 9. Contents A bit more on Locks Deadlock Race conditions Starvation Non-atomic operations. Locks. Every object has a lock You lock an object by synchronizing on it

knalley
Download Presentation

Component-Based Software Engineering

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Component-Based Software Engineering Understanding Thread Safety Paul Krause

  2. Lecture 9 Contents • A bit more on Locks • Deadlock • Race conditions • Starvation • Non-atomic operations

  3. Locks • Every object has a lock • You lock an object by synchronizing on it public void addElement(Object item) { synchroniized(myArrayList) { // do the stuff } } public boolean elementExists(Object item) { return myArrayList.contains(item) } • To be absolutely accurate, synchronize on access methods too

  4. What to Lock? public class McBurgerPlace { private static Person ceo = new Person(); private Object floor; private Object sodaFountain; public static synchronized Person receiveCeo() { return ceo; } public synchronized void waxFloor() {// do stuff … } public Object getSodaFountain() { synchronized(sodaFountain) { // do stuff … } } }

  5. Non-implicit locking • If threadA is receiving the ceo, can threadB wax the floor? • If threadB is waxing the floor, can threadC get the soda fountain? • The answer is Yes in both cases • The JVM doesn’t do nested locking

  6. Locking objects not members public class LockObjectNotMemberVariables { private List myList = new ArrayList(); public static void main(String[] args) { LockObjectNotMemberVariables lonmv = new LockObjectNotMemberVariables(); lonmv.lockTest(); } public synchronized void lockTest() { System.out.println("Is THIS object locked? " + Thread.holdsLock(this)); System.out.println("Is the list object locked? " + Thread.holdsLock(myList)); } }

  7. Locking objects not members init: deps-jar: Created dir: /Users/paulkrause/Java/threading/build/classes Compiling 1 source file to /Users/paulkrause/Java/threading/build/classes compile-single: run-single: Is THIS object locked? true Is the list object locked? false BUILD SUCCESSFUL (total time: 4 seconds)

  8. Locking classes not instances public class ClassLockNotObjectLock { public static void main(String[] args) { lockTest(); } public static synchronized void lockTest() { ClassLockNotObjectLock clnol = new ClassLockNotObjectLock(); System.out.println("Is the Class locked? " + Thread.holdsLock(clnol.getClass())); System.out.println("Is the object instance locked? " + Thread.holdsLock(clnol)); } }

  9. Locking classes not instances init: deps-jar: Compiling 1 source file to /Users/paulkrause/Java/threading/build/classes compile-single: run-single: Is the Class locked? true Is the object instance locked? false BUILD SUCCESSFUL (total time: 4 seconds)

  10. What to lock? • Synchronising on Objects other than “this” provides more concurrency • But controlling locks on such a fine scale can be inefficient if a method needs to access several objects • The safest general policy is not to allow unsynchronized access to the resources you need to lock and synchronize methods

  11. Thread Safety Examples • Deadlock • First thread gets Lock 1 and then tries to get Lock 2 • Second thread gets Lock 2 and then tries to get Lock 1 • Race Conditions • Two threads race for a common object • Starvation • A thread is never/rarely allowed to execute

  12. Deadlock public void run() { String name = Thread.currentThread().getName(); synchronized(lockA) { System.out.println(name + ": locked" + lockA); delay(name); System.out.println(name + ": trying to get " + lockB); synchronized(lockB) { System.out.println(name + ": locked" + lockB); } } }

  13. Example run init: deps-jar: Compiling 1 source file to /Users/paulkrause/Java/threading/build/classes compile-single: run-single: Thread-0: lockedLock 1 Thread-0: delaying 1 second Thread-1: lockedLock 2 Thread-1: delaying 1 second Thread-0: trying to get Lock 2 Thread-1: trying to get Lock 1  Both threads now blocked

  14. Race condition example if (Math.random() > .5) { peter.start(); paul.start(); } else { paul.start(); peter.start(); }

  15. Race condition example public void run() { System.out.println(getName() + ": trying for lock on " + server); synchronized(server) { System.out.println(getName() + ": has lock on " + server); // wait 2 seconds: show the other thread is really // blocked try { Thread.sleep(2000); } catch (InterruptedException ie) { ie.printStackTrace(); } System.out.println(getName() + ": releasing lock "); }

  16. Example run (I) run-single: Peter: trying for lock on the common object Peter: has lock on the common object Paul: trying for lock on the common object Peter: releasing lock Paul: has lock on the common object Paul: releasing lock BUILD SUCCESSFUL (total time: 5 seconds)

  17. Example run (II) run-single: Paul: trying for lock on the common object Paul: has lock on the common object Peter: trying for lock on the common object Paul: releasing lock Peter: has lock on the common object Peter: releasing lock BUILD SUCCESSFUL (total time: 8 seconds)

  18. Starvation Example for (int i = 0; i < 4; i++) { // create a runner Runner r = new Runner(); r.setPriority(Thread.MAX_PRIORITY); // set the first thread to starve if (i == 0) { r.setPriority(Thread.MIN_PRIORITY); r.setName("Starvation Thread"); } // start the thread r.start(); r.yield(); // optional line }

  19. run-single: Starvation Thread: is working 10 Thread-1: is working 10 Thread-2: is working 10 Thread-1: is working 9 Thread-2: is working 9 Thread-1: is working 8 Thread-2: is working 8 Thread-1: is working 7 Thread-2: is working 7 Thread-1: is working 6 Thread-2: is working 6 Thread-1: is working 5 Thread-2: is working 5 Thread-1: is working 4 Thread-2: is working 4 Thread-1: is working 3 Thread-2: is working 3 Thread-1: is working 2 Thread-2: is working 2 Thread-1: is working 1 Thread-2: is working 1 Thread-3: is working 10 Thread-3: is working 9 Thread-3: is working 8 Thread-3: is working 7 Thread-3: is working 6 Thread-3: is working 5 Thread-3: is working 4 Thread-3: is working 3 Thread-3: is working 2 Thread-3: is working 1 Starvation Thread: is working 9 Starvation Thread: is working 8 Starvation Thread: is working 7 Starvation Thread: is working 6 BUILD SUCCESSFUL (total time: 1 second) Example run

  20. Atomic Operations • Synchronization blocks some code as “atomic” • A thread will not be swapped out in the middle of an atomic operation • Be careful in assuming any statements are atomic!

  21. Non-atomic operations • x = 45; • Is atomic if x is an int • Is not atomic if x is double or long • One operation for the high 32 bits, one for the low 32 bits

  22. Non-atomic operations • Treat x = 7; y = x++; • As x = 7; int temp = x + 1; x = temp; y = x; A thread swap here could lead to unexpected results

  23. Class NonAtomic.java • Class has a static variable • static int x; • The start ten threads that each do the following: for (int i= 0; i < 10; i++) { int reference = (int) (Math.random() * 100); x = reference; // some calculation to make a slight delay if (x == reference) { validCounts++; } else { invalidCounts++; } }

  24. Example run run-single: Thread-1 valid: 10 invalid: 0 Thread-6 valid: 10 invalid: 0 Thread-0 valid: 9 invalid: 1 Thread-3 valid: 7 invalid: 3 Thread-7 valid: 8 invalid: 2 Thread-8 valid: 7 invalid: 3 Thread-4 valid: 5 invalid: 5 Thread-9 valid: 8 invalid: 2 Thread-2 valid: 6 invalid: 4 Thread-5 valid: 6 invalid: 4 BUILD SUCCESSFUL (total time: 3 seconds)

  25. Problem fixed for (int i= 0; i < 10; i++) { synchronized(NonAtomic.class) { int reference = (int) (Math.random() * 100); x = reference; // Do something intensive here if (x == reference) { validCounts++; } else { invalidCounts++; } }

  26. New run run-single: Thread-0 valid: 10 invalid: 0 Thread-7 valid: 10 invalid: 0 Thread-2 valid: 10 invalid: 0 Thread-1 valid: 10 invalid: 0 Thread-5 valid: 10 invalid: 0 Thread-3 valid: 10 invalid: 0 Thread-8 valid: 10 invalid: 0 Thread-6 valid: 10 invalid: 0 Thread-9 valid: 10 invalid: 0 Thread-4 valid: 10 invalid: 0 BUILD SUCCESSFUL (total time: 3 seconds)

More Related