Effective Java: Concurrency - PowerPoint PPT Presentation

1 / 20
About This Presentation
Title:

Effective Java: Concurrency

Description:

Examples: Collection classes. Thread hostile: Not to be emulated! ... Double-check idiom for lazy initialization of instance fields ... – PowerPoint PPT presentation

Number of Views:46
Avg rating:3.0/5.0
Slides: 21
Provided by: richardb45
Category:

less

Transcript and Presenter's Notes

Title: Effective Java: Concurrency


1
Effective JavaConcurrency
  • Last Updated Fall 2009

2
Agenda
  • Material From Joshua Bloch
  • Effective Java Programming Language Guide
  • Cover Items 66-73
  • Concurrency Chapter
  • Bottom Line
  • Primitive Java concurrency is complex

3
Item 66 Synchronize Access to Shared Mutable Data
  • Method synchronization yields atomic transitions
  • public synchronized boolean doStuff()
  • Fairly well understood
  • Method synchronization also ensures that other
    threads see earlier threads
  • Not synchronizing on shared atomic data
    produces wildly counterintuitive results
  • Not well understood

4
Item 66 Unsafe Example
  • // Broken! How long do you expect this program
    to run?
  • public class StopThread
  • private static boolean stopRequested
  • public static void main (String args)
  • throws InterruptedException
  • Thread backgroundThread new Thread(new
    Runnable()
  • public void run() // May
    run forever!
  • int io while (! stopRequested) i
    // See below
  • )
  • backgroundThread.start()
  • TimeUnit.SECONDS.sleep(1)
  • stopRequested true
  • // Hoisting transform
  • // while (!loopTest) i ? if (!loopTest)
    while(true) i
  • // Also note anonymous class

5
Item 66 Fixing the Example
  • // As before, but with synchronized calls
  • public class StopThread
  • private static boolean stopReq
  • public static synchronized void setStop()
    stopReq true
  • public static synchronized void getStop()
    return stopReq
  • public static void main (String args)
  • throws InterruptedException
  • Thread backgroundThread new Thread(new
    Runnable()
  • public void run() // Now sees main
    thread
  • int io while (! getStop() ) i
  • )
  • backgroundThread.start()
  • TimeUnit.SECONDS.sleep(1)
  • setStop()
  • // Note that both setStop() and getStop() are
    synchronized

6
Item 66 A volatile Fix for the Example
  • // A fix with volatile
  • public class StopThread
  • // Pretty subtle stuff, using the volatile
    keyword
  • private static volatile boolean stopRequested
  • public static void main (String args)
  • throws InterruptedException
  • Thread backgroundThread new Thread(new
    Runnable()
  • public void run()
  • int io while (! stopRequested) i
  • )
  • backgroundThread.start()
  • TimeUnit.SECONDS.sleep(1)
  • stopRequested true

7
Item 66 volatile Does Not Guarantee Mutual
Exclusion
  • // Broken! Requires Synchronization!
  • private static volatile int nextSerialNumber 0
  • public static int generateSerialNumber()
  • return nextSerialNumber
  • Problem is that the operator is not atomic
  • // Even better! (See Item 47)
  • private static final AtomicLong nextSerial new
    AtomicLong()
  • public static long generateSerialNumber()
  • return nextSerial.getAndIncrement()

8
Item 66 Advice on Sharing Data Between Threads
  • Confine mutable data to a single Thread
  • May modify, then share (no further changes)
  • Called Effectively Immutable
  • Allows for Safe Publication
  • Mechanisms for safe publication
  • In static field at class initialization
  • volatile field
  • final field
  • field accessed with locking (ie synchronization)
  • Store in concurrent collection (Item 69)

9
Item 67 Avoid Excessive Synchronization
  • // Broken! Invokes alien method from sychronized
    block
  • public interface SetObltEgt void
    added(ObservableSetltEgt set, E el)
  • public class ObservableSetltEgt extends
    ForwardingSetltEgt // Bloch 16
  • public ObservableSet(SetltEgt set) super(set)
  • private final ListltSetObltEgtgt obs new
    ArrayListltSetObltEgtgt()
  • public void addObserver (SetObsltEgt ob )
  • synchronized (obs) obs.add(ob)
  • public boolean removeObserver (SetObltEgt ob )
  • synchronized (obs) return obs.remove(ob)
  • private void notifyElementAdded (E el)
  • synchronized(obs) for (SetObltEgt obobs) //
    Exceptions?
  • ob.added(this, el)
  • _at_Override public boolean add(E el) // from
    Set interface
  • boolean added super.add(el)
  • if (added) notifyElementAdded (el)
  • return added

10
More Item 67 Whats the Problem?
  • public static void main (String args)
  • ObservableSetltIntegergt set new
    ObservableSetltIntegergt
  • (new HashSetltIntegergt)
  • set.addObserver (new SetObltIntegergt()
  • public void added (ObservableSetltIntegergt
    s, Integer e)
  • System.out.println(e)
  • if (e.equals(23)) s.removeObserver(this)
    // Oops! CME
  • // See Bloch for a variant that
    deadlocks instead of CME
  • )
  • for (int i0 i lt 100 i)
  • set.add(i)

11
More Item 67 Turning the Alien Call into an Open
Call
  • // Alien method moved outside of synchronized
    block open call
  • private void notifyElementAdded(E el)
  • ListltSetObltEgtgt snapshot null
  • synchronized (observers)
  • snapshot new ArrayListltSetObltEgtgt(obs)
  • for (SetObserverltEgt observer snapshot)
  • observer.added(this, el) // No more CME
  • Open Calls increase concurrency and prevent
    failures
  • Rule Do as little work inside synch block as
    possible
  • When designing a new class
  • Do NOT internally synchronize absent strong
    motivation
  • Example StringBuffer vs. StringBuilder

12
Item 67 Alternate Fix Using CopyOnWriteArray
  • public interface SetObltEgt void
    added(ObservableSetltEgt set, E el)
  • public class ObservableSetltEgt extends
    ForwardingSetltEgt // Bloch 16
  • public ObservableSet(SetltEgt set) super(set)
  • private final ListltSetObltEgtgt obs new
  • CopyOnWriteArrayListltSetObltEgtgt()
  • public void addObserver (SetObsltEgt ob )
  • synchronized (obs) obs.add(ob)
  • public boolean removeObserver (SetObltEgt ob )
  • synchronized (obs) return obs.remove(ob)
  • private void notifyElementAdded (E el)
  • for (SetObltEgt obobs) // Iterate on copy
    No Synch!
  • ob.added(this, el)
  • _at_Override public boolean add(E el) // from
    Set interface
  • boolean added super.add(el)
  • if (added) notifyElementAdded (el)
  • return added

13
Item 68 Prefer Executors and Tasks to Threads
  • Old key abstraction Thread
  • Unit of work and
  • Mechanism for execution
  • New key abstractions
  • Task (Unit of work)
  • Runnable and Callable
  • Mechanism for execution
  • Executor Service
  • Start tasks, wait on particular tasks, etc.
  • See Bloch for references

14
Item 69 Prefer Concurrency Utilities to wait and
notify
  • wait() and notify() are complex
  • Java concurrency facilities much better
  • Legacy code still requires understanding low
    level primitives
  • Three mechanisms
  • Executor Framework (Item 68)
  • Concurrent collections
  • Internally synchronized versions of Collection
    classes
  • Extensions for blocking, Example BlockingQueue
  • Synchronizers
  • Objects that allow Threads to wait for one another

15
More Item 69 Timing Example
  • // Simple framework for timing concurrent
    execution
  • public static long time (Executor executor, int
    concurrency, final Runnable action) throws
    InterrruptedExecution
  • final CountDownLatch ready new
    CountDownLatch(concurrency)
  • final CountDownLatch start new
    CountDownLatch(1)
  • final CountDownLatch done new
    CountDownLatch(concurrency)
  • for (int i0 ilt concurrency i)
  • executor.execute (new Runnable()
  • public void run() ready.countDown()
    // Tell Timer were ready
  • try start.await() action.run()
    // Wait till peers are ready
  • catch (...) ...
  • finally done.countDown() //
    Tell Timer were done
  • )
  • ready.await() // Wait for all workers
    to be ready
  • long startNanos System.nanoTime()
  • start.countDown() // And theyre off!
  • done.await() // Wait for all workers
    to finish
  • return System.nanoTime() startNanos

16
Item 70 Document Thread Safety
  • Levels of Thread safety
  • Immutable
  • Instances of class appear constant
  • Example String
  • Unconditionally thread-safe
  • Instances of class are mutable, but is internally
    synchronized
  • Example ConcurrentHashMap
  • Conditionally thread-safe
  • Some methods require external synchronization
  • Example Collections.synchronized wrappers
  • Not thread-safe
  • Client responsible for synchronization
  • Examples Collection classes
  • Thread hostile Not to be emulated!

17
Item 71 Use Lazy Initialization Judiciously
  • Under most circumstances, normal initialization
    is preferred
  • // Normal initialization of an instance field
  • private final FieldType field
    computeFieldValue()
  • // Lazy initialization of instance field
    synchronized accessor
  • private FieldType field
  • synchronized FieldType getField()
  • if (field null)
  • field computeFieldValue()
  • return field

18
More Item 71 Double Check Lazy Initialization
  • // Double-check idiom for lazy initialization of
    instance fields
  • private volatile FieldType field // volatile
    key see Item 66
  • FieldType getField()
  • FieldType result field
  • if (result null) // check with no
    locking
  • synchronized (this)
  • result field
  • if (result null) // Second check with
    a lock
  • field result computeFieldValue()
  • return result

19
Item 72 Dont Depend on the Thread Scheduler
  • Any program that relies on the thread scheduler
    is likely to be unportable
  • Threads should not busy-wait
  • Use concurrency facilities instead (Item 69)
  • Dont Fix slow code with Thread.yield calls
  • Restructure instead
  • Avoid Thread priorities

20
Item 73 Avoid Thread Groups
  • Thread groups originally envisioned as a
    mechanism for isolating Applets for security
    purposes
  • Unfortunately, doesnt really work
Write a Comment
User Comments (0)
About PowerShow.com