• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Concurrency
 

Concurrency

on

  • 1,599 views

 

Statistics

Views

Total Views
1,599
Views on SlideShare
1,514
Embed Views
85

Actions

Likes
2
Downloads
36
Comments
0

5 Embeds 85

http://chawlasandeep.com 75
http://www.linkedin.com 4
http://localhost 4
http://prlog.ru 1
https://www.linkedin.com 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Concurrency Concurrency Presentation Transcript

    • [Effective Java by Joshua Bloch]
    • Item 1 2
    • Synchronization ensures:1) Mutual exclusion i.e. to prevent an object from being observed in an inconsistent state while it’s being modified by another thread.2) Reliable communication between the threads i.e. each thread entering a synchronized method or block sees the effects of all previous modifications that were guarded by the same lock.When the JVM executes a synchronized method, it acquires a lock on thatobject. if one synchronized method owns a lock, no other synchronized method can run until the lock is released only one lock on an object at a time lock is released when the method is finished 3
    • FEW MISCONCEPTIONS (SHOULD BE AVOIDED): To improve performance, do not avoid synchronization when reading or writing atomic data. Coz the language specification i.e. memory model guarantees that a thread will not see an arbitrary value when reading a field, it does not guarantee that a value written by one thread will be visible to another. Thus, Synchronization has no effect unless both read and write operations are synchronized. In a multi-threaded environment, any mutable data visible to more than one thread must be referenced within a synchronized block. This includes all primitive data. All get and set methods for shared data which can change must be synchronized. It is a misconception that all primitives except long and double do not need synchronized access. 4
    • The penalties for failing to synchronize shared mutable data are: 1) Safety failures 2) Liveness failuresThese failures are among the most difficult to debug.Safety Hazards:Thread safety can be unexpectedly subtle because, in the absence of sufficientsynchronization, the ordering of operations in multiple threads is unpredictable andsometimes surprising.Consider a class UnsafeSequence, which is supposed to generate a sequence of uniqueinteger values.public class UnsafeSequence { private int value; /** Returns a unique value. */ public int getNext() { return value++; }} 5
    • The problem with UnsafeSequence is that with some unlucky timing, two threads could callgetNext and receive the same value as shown in the following figure:Reason for above behaviour is:The increment notation, nextValue++, denotes three separate operations: read thevalue, add one to it, and write out the new value. Since operations in multiple threads may be arbitrarily interleaved by theruntime, it is possible for two threads to read the value at the same time, both see thesame value, and then both add one to it. The result is that the same sequence number isreturned from multiple calls in different threads. 6
    • Solution: For a multithreaded programs behavior to be predictable, access toshared variables must be properly coordinated so that threads do not interferewith one another. Fortunately, Java provides synchronization mechanisms tocoordinate such access.UnsafeSequence can be fixed by making getNext a synchronized method, asshown :public class Sequence { private int nextValue; public synchronized int getNext() { return nextValue++; }} 7
    • Liveness Hazards:A liveness failure occurs when an activity gets into a state such that it is permanently unableto make forward progress. liveness failure that can occur in sequential programs is an inadvertent infinite loop, where the code that follows the loop never gets executed. The use of threads introduces additional liveness risks. For example, if thread A is waiting for a resource that thread B holds exclusively, and B never releases it, A will wait forever. This is called deadlock. Other Liveness Hazards include starvation and livelock. Starvation occurs when a thread is perpetually denied access to resources it needs in order to make progress. Starvation in Java applications can be caused by inappropriate use of thread priorities or by executing non-terminating constructs (infinite loops or resource waits that do not terminate) with a lock held 8
    •  Livelock is a form of liveness failure in which a thread, while not blocked, still cannot make progress because it keeps retrying an operation that will always fail. Livelock often occurs in transactional messaging applications, where the messaging infrastructure rolls back a transaction if a message cannot be processed successfully, and puts it back at the head of the queue. If a bug in the message handler for a particular type of message causes it to fail, every time the message is dequeued and passed to the buggy handler, the transaction is rolled back. Since the message is now back at the head of the queue, the handler is called over and over with the same result. (This is sometimes called the poison message problem.) The message handling thread is not blocked, but it will never make progress either. This form of livelock often comes from overeager error‐recovery code that mistakenly treats an unrecoverable error as a recoverable one. 9
    • Volatile Variables Shared variable, no re-ordering with other memory operations Never cached in registers or CPU caches Read always returns the most recent write by any thread Used for: Ensuring visibility of their own state Ensuring visibility of the object they refer to Indicating an important lifecycle (init/shutdown) event Completion, interruption, status flag Used when: Writes do not depend on current value Unless a single thread only updates the variable Doesn’t participate in invariants with other state variables Locking is not required for any other reason while accessed Locking = visibility + atomicity Volatile = visibility only! Writes and reads of volatile fields have similar memory consistency effects as entering and exiting monitors, but do not entail mutual exclusion locking. 10
    • You can use volatile variables only when all the following criteria are met: Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever updates the value; The variable does not participate in invariants with other state variables; and Locking is not required for any other reason while the variable is being accessed. 11
    •  Item 2 12
    •  synchronize your class internally only if there is a good reason to do so, and document your decision clearly . synchronize if one or more threads will access the same object or field. do not synchronize an entire method if only parts of the method need to be synchronized public void myMethod() { synchronize(this) { // code that needs to be synchronized } // code that is already thread-safe } do not synchronize a method that uses only local variables: //a method which should not be synchronized public int square(int n) { int s = n * n; return s; } 13
    •  Do as little as possible inside synchronized region. Obtain the lock, examine the shared data, transform the data as necessary, and drop the lock. If a class could be used both in circumstances requiring synchronization and circumstances where synchronization not required, provide both the variants through wrapper class or subclass with synchronization. inside a synchronized region, do not invoke a method that is designed to be overridden, or one provided by a client in the form of a function object. From the perspective of the class with the synchronized region, such methods are alien. The class has no knowledge of what the method does and has no control over it. Depending on what an alien method does, calling it from a synchronized region can cause exceptions, deadlocks, or data corruption. 14
    •  Item 3 15
    •  Java 5.0 provides higher-level concurrency utilities that do the sorts of things you formerly had to hand-code atop wait and notify. If you maintain code that uses wait and notify, make sure that it always invokes wait from within a while loop using the standard idiom. The notifyAll method should generally be used in preference to notify. If notify is used, great care must be taken to ensure liveness.Concurrency utilities are the classes which are designed to be used as buildingblocks in building concurrent classes or applications. Using these to implement aconcurrent application can help you make your programclearer, shorter, faster, more reliable, more scalable, easier to write, easier toread, and easier to maintain. It fall into three categories:  Executor Framework  Concurrent collection  Synchronizers 16
    • Executor framework java.util.concurrent provides a flexible thread pool implementation as part of the Executor framework. The primary abstraction for task execution in the Java class libraries is not Thread, but Executor, as shown: public interface Executor { void execute(Runnable command); } Executor may be a simple interface, but it forms the basis for a flexible and powerful framework for asynchronous task execution that supports a wide variety of task execution policies. Executor is based on the producer‐consumer pattern, where activities that submit tasks are the producers (producing units of work to be done) and the threads that execute tasks are the consumers (consuming those units of work). Using an Executor is usually the easiest path to implementing a producer‐consumer design in your application. 17
    •  You can do many more things with an executor service. For example,  you can wait for a particular task to complete  you can wait for any or all of a collection of tasks to complete(using the invokeAny or invokeAll methods),  you can wait for the executor service’s graceful termination to complete (using the awaitTermination method),  you can retrieve the results of tasks one by one as they complete (using an ExecutorCompletionService), and so on. 18
    • Concurrent Collections Replacing synchronized collections with concurrent collections can offer dramatic scalability improvements with little risk. Synchronized collections achieve their thread safety by serializing all access to the collections state. The cost of this approach is poor concurrency; when multiple threads contend for the collection‐wide lock, throughput suffers. The concurrent collections, on the other hand, are designed for concurrent access from multiple threads.Java 5.0 adds ConcurrentHashMap, a replacement for synchronized hash‐based Map implementations.The synchronized collections classes hold a lock for the duration of each operation. Someoperations, such as HashMap.get or List.contains, may involve more work and thus cantake a long time, and during that time no other thread can access the collection. 19
    • ConcurrentHashMap is also a hash‐based, but it uses an entirely different locking strategythat offers better concurrency and scalability. Instead of synchronizing every method on a common lock, restricting access to a single thread at a time, it uses a finer‐grained locking mechanism called lock striping to allow a greater degree of shared access. It basically uses an array of 16 locks, each of which guards 1/16 of the hash buckets; bucket N is guarded by lock N mod 16. this enables ConcurrentHashMap to support up to 16 concurrent writers. It allows many reading threads to access the map concurrently. Even readers can access the map concurrently with writers, and a limited number of writers can modify the map concurrently. It provides iterators that do not throw ConcurrentModificationException, thus eliminating the need to lock the collection during iteration. 20
    • Java 5.0 also adds BlockingQueue. It extends Queue to add blocking insertion and retrieval operations. If the queue is empty, a retrieval blocks until an element is available, and if the queue is full (for bounded queues) an insertion blocks until there is space available. Blocking queues are extremely useful in producer‐consumer designs.Java 5.0 also gives CopyOnWriteArrayList. It is a variant of ArrayList in which all write operations are implemented by making a fresh copy of the entire underlying array. Because the internal array is never modified, iteration requires no locking and is very fast. It’s perfect for observer lists, which are rarely modified and often traversed. 21
    • Synchronizers A synchronizer is any object that coordinates the control flow of threads based on its state. Blocking queues can act as synchronizers; other types include semaphores, barriers, and latches. All synchronizers share certain structural properties: they encapsulate state that determines whether threads arriving at the synchronizer should be allowed to pass or forced to wait, provide methods to manipulate that state, and provide methods to wait efficiently for the synchronizer to enter the desired state. A latch is a synchronizer that can delay the progress of threads until it reaches its terminal state. A latch acts as a gate: until the latch reaches the terminal state the gate is closed and no thread can pass, and in the terminal state the gate opens, allowing all threads to pass. Once the latch reaches the terminal state, it cannot change state again, so it remains open forever. 22
    • Latches can be used to ensure that certain activities do not proceed until other one‐time activities complete, such as: Ensuring that a computation does not proceed until resources it needs have been initialized. A simple binary (two‐state) latch could be used to indicate "Resource R has been initialized", and any activity that requires R would wait first on this latch. Ensuring that a service does not start until other services on which it depends have started. Each service would have an associated binary latch; starting service S would involve first waiting on the latches for other services on which S depends, and then releasing the S latch after startup completes so any services that depend on S can then proceed. Waiting until all the parties involved in an activity, for instance the players in a multi‐player game, are ready to proceed. In this case, the latch reaches the terminal state after all the players are ready. 23
    • CountDownLatch is a flexible latch implementation that can be used in any ofthese situations; it allows one or more threads to wait for a set of events tooccur.The latch state consists of a counter initialized to a positive number,representing the number of events to wait for.The countDown method decrements the counter, indicating that an event hasoccurred, and the await methods wait for the counter to reach zero, whichhappens when all the events have occurred.If the counter is nonzero on entry, await blocks until the counter reacheszero, the waiting thread is interrupted, or the wait times out. 24
    •  Item 4 25
    • How many times have you looked at the Javadoc for a class, and wondered, "Isthis class thread-safe?"In the absence of clear documentation, readers may make bad assumptionsabout a classs thread safety. theyll just assume it is thread-safe when its not (thats really bad!), or maybe theyll assume that it can be made thread-safe by synchronizing on the object before calling one of its methods (which may be correct, or may simply be inefficient, or in the worst case, could provide only the illusion of thread safety).Thus, Write it down before you forget it (or leave the company). The best time to document thread safety is definitely when the class is first written -- it is much easier to assess the thread safety requirements and behavior of a class when you are writing it than when you (or someone else) come back to it months later. 26
    • Thread SafetyA class is thread‐safe if it first must behave correctly in a single-threaded environment.And further, it behaves correctly when accessed from multiple threads, regardless of thescheduling or interleaving of the execution of those threads by the runtimeenvironment, and with no additional synchronization or other coordination on the part of thecalling code.To enable safe concurrent use, a class must clearly document what level of thread safety itsupports. Bloch has outlined a taxonomy that describes five categories of thread safety.Though it does not cover all possible cases, its a very good start.:1) Immutable: Immutable objects are guaranteed to be thread-safe, and never require additional synchronization. Because an immutable objects externally visible state never changes, as long as it is constructed correctly, it can never be observed to be in an inconsistent state. Example: Most of the basic value classes in the Java class libraries, such as Integer, String, and BigInteger, are immutable. 27
    • 2) UnConditionally thread-safe : Instances of this class are mutable, but the class has sufficient internal synchronization that its instances can be used concurrently without the need for any external synchronization. Examples: Random and ConcurrentHashMap classes.3) Conditionally thread-safe classes are those for which each individual operation may be thread-safe, but certain sequences of operations may require external synchronization. Example: traversing an iterator returned from Hashtable or Vector classes.The iterators returned assumes that the underlying collection will not be mutated while theiterator traversal is in progress. To ensure that other threads will not mutate the collectionduring traversal, the iterating thread should acquire exclusive access by synchronizing on alock. -- and the classs documentation should specify which lock that is (typically the objectsintrinsic monitor). 28
    •  Conditionally thread-safe classes must document which method invocation sequences require external synchronization, and which lock to acquire when executing these sequences. If you write an unconditionally thread-safe class, consider using a private lock object in place of synchronized methods. Because when a class commits to using a publicly accessible lock, a client can mount a denial-of-service attack by holding the publicly accessible lock for a prolonged period which can be accidental or intentional. The private lock object is inaccessible to clients of the class, it is impossible for them to interfere with the object’s synchronization.4) Not thread-safe: Instances of this class are mutable. To use them concurrently, clients must surround each method invocation (or invocation sequence) with external synchronization of the clients’ choosing. Example: general-purpose collection implementations, such as ArrayList and HashMap. 29
    • 5) Thread-hostile : Thread-hostile classes are those that cannot be rendered safe to use concurrently, regardless of what external synchronization is invoked. Thread hostility is rare, and typically arises when a class modifies static data that can affect the behavior of other classes that may execute in other threads. An example of a thread-hostile class would be one that calls System.setOut(). Luckily, there are very few thread-hostile classes or methods in the Java libraries. 30
    •  By documenting that a class is thread-safe (assuming it actually is thread- safe), you perform two valuable services: i. you inform maintainers of the class that they should not make modifications or extensions that compromise its thread safety, and ii. you inform users of the class that it can be used without external synchronization. By documenting that a class is thread-compatible or conditionally thread-safe, you inform users that the class can be used safely by multiple threads through the appropriate use of synchronization. By documenting that a class is thread-hostile, you inform users that they cannot use the class safely from multiple threads, even with external synchronization. In each case, you are preventing potentially serious bugs, which would be expensive to find and fix, before they happen. 31
    •  Item 5 32
    • Lazy initialization means that you do not initialize objects until the first time they are used.It can be a useful performance-tuning technique. When you have thousands of objects that need complex initializations but only a few will actually be used, lazy initialization provides a significant speedup to an application by avoiding exercising code that may never be run. when there are many objects that need to be created and initialized, and most of these objects will be used, but not immediately. In this case, it can be useful to spread out the load of object initialization.Lazy initialization has its uses. But in the presence of multiple threads, lazy initialization istricky. If two or more threads share a lazily initialized field, it is critical that some form ofsynchronization be employed, or severe bugs can result. So Under mostcircumstances, normal initialization is preferable to lazy initialization. 33
    • // Normal initialization of an instance fieldprivate final Resource resource = new Resource();// Lazy initialization of instance field - synchronized accessor@ThreadSafepublic class SafeLazyInitialization { private static Resource resource; public synchronized static Resource getInstance() { if (resource == null) resource = new Resource(); return resource; }} 34
    • If you must initialize a field lazily in order to achieve your performance goals, or to break aharmful initialization circularity, then use the appropriate lazy initialization technique: Lazy initialization holder class idiom: It uses a class whose only purpose is to initialize the Resource. The JVM defers initializing the ResourceHolder class until it is actually used and because the Resource is initialized with a static initializer, no additional synchronization is needed. The first call to getresource by any thread causes ResourceHolder to be loaded and initialized, at which time the initialization of the Resource happens through the static initializer.@ThreadSafepublic class ResourceFactory { private static class ResourceHolder { public static Resource resource = new Resource(); } public static Resource getResource() { return ResourceHolder.resource ; }} 35
    • Double-checked Idiom :It is the technique of choice for lazily initializing an instance field. It purported to offer the best of both worlds ‐ lazy initialization without paying the synchronization penalty on the common code path. The way it worked was first to check whether initialization was needed without synchronizing, and if the resource reference was not null, use it. Otherwise, synchronize and check again if the Resource is initialized, ensuring that only one thread actually initializes the shared Resource.public class DoubleCheckedLocking { private volatile Resource resource; public Resource Resource getInstance() { if (resource == null) { synchronized (DoubleCheckedLocking.class) { if (resource == null) resource = new Resource(); } } return resource; }} 36
    • The common code path ‐- fetching a reference to an already constructed Resource doesntuse synchronization.Single-check Idiom:  It is a variant of the double-check idiom that dispenses with the second check.  Used to lazily initialize an instance field that can tolerate repeated initialization.// Single-check idiom - can cause repeated initialization!private volatile Resource resource;private Resource getInstance() { Resource result = resource; if (result == null) resource = result = new Resource(); return result;} 37
    •  Item 6 38
    •  When many threads are runnable, the thread scheduler determines which ones get to run, and for how long. Any reasonable operating system will try to make this determination fairly, but the policy can vary. Therefore, well-written programs shouldn’t depend on the details of this policy. Any program that relies on the thread scheduler for correctness or performance is likely to be non-portable. You must ensure that the average number of runnable threads is not significantly greater than the number of processors. This leaves the thread scheduler with little choice: it simply runs the runnable threads till they’re no longer runnable. The program’s behavior doesn’t vary too much, even under radically different thread-scheduling policies. Threads should not run if they aren’t doing useful work. The main technique for keeping the number of runnable threads down is to have each thread do some useful work and then wait for more. 39
    •  When faced with a program that barely works because some threads aren’t getting enough CPU time relative to others, do not rely on Thread.yield to “fix” the program for it will make your program non-portable. It may improve performance on one JVM implementation might make it worse on a second and have no effect on a third. So a better options is to restructure the application to reduce the number of concurrently runnable threads. Thread priorities are among the least portable features of the Java platform. Thread priorities may be used sparingly to improve the quality of service of an already working program, but they should never be used to “fix” a program that barely works. 40
    •  Item 7 41
    •  A thread group holds a collection of threads. For example, your program can use ThreadGroup to group all printing threads into one group. Thread groups were originally envisioned as a mechanism for isolating applets for security purposes. They never really fulfilled this promise, and their security importance has waned to the extent that they aren’t even mentioned in the standard work on the Java security model. Thread groups don’t provide much in the way of useful functionality, and much of the functionality they do provide is flawed. Thread groups are best viewed as an unsuccessful experiment, and you should simply ignore their existence. If you design a class that deals with logical groups of threads, you should probably use thread pool executors 42