I want to look into multi threading and I am reading "Java Concurrency In Practice". Some of the notes which are helpful are below -
When we are writing Java/J2ee programs, we are aware that our program would run inside a multithreaded environment. Our frameworks are multithreaded, servers aree multithreaded, and
JVM is multithreaded. Timer, Servelet, RMI, Swing are all inherently multithreaded, and we should take caution while writing any data, sharing state, and creating data.
Some places where Multi threading is required, apart from the common use
i.e., to fully utilize the hardware, multiple processors. To increase speed, responsiveness of application.
1. Need to start multiple threads rather than making single threaded program more intelligent. If application goes to read from a socket, and no data is available, the thread is blocked. To avoid this problem, single threaded server applications are forced to use Non blocking I/O. NIO is far more complicated and error-prone than synchronous I/O. Multithreading is better approach. If each request is handled in separate thread, the blocking on thread doesn't block other requests.
2. To make application more responsive use multithreading instead of always going for asynchronous. Lot of tasks today are asynchronous, Some are huge and complicated. A complicated, asynchronous workflow can be decomposed into a number of simpler synchronous workflows each running in a separate thread, interacting only with each other at specific synchronization points. We can have a framework. Framework manages request, thread creation, load balancing, and dispatching requests to appropriate handler. Author of handler need not to worry about how many simultaneous requests are handled.
3. User multithreading to avoid delays. One big task, one big transaction, and one big server should not be always preferred. One big task can be broke into separate threads and still be bound in one transaction with no requirement of extra hardware.
Already Thread Safe(Ways we can probably avoid the synchronized block) -
1. Thread Confinement - When an object is confined to a thread, such usage is thread safe, even if the confined object is not thread safe.
Like in pooled JDBC connection objects, the connection object might not be thread safe, but poolis thread safe,
and pool doesn't dispense the same connection to another thread, unless it returns to the pool.
"ThreadLocal" associates a per thread value witha value holding object.
"ThreadLocal" provides get and set accessor methods that maintain a separate copy of value forneach thread that uses it.
Conceptually its like Map, where Thread is thread and T is thread specific value.
The thread specific valuyes are stored iin the thread itself.
For eg., in an EJB call, the J2EE container associate transaction context with an executing thread for the duration of the EJB call.
This helps container easily determine what transaction is currently running.
2. Stack Confinement - Local Variables are thread safe, local variables can be used to confine objects to a thread.
3. Immutable objects are always thread safe. A properly consturcted(this doesn't escapes), and state can't be modified,
and may be all fields are final. No requirement for safe publication.
Note -> Its good practice to make fields private, unless they need visibility.
Its good practice to make fields final, unless they need to be muatble.
Whenever a group of related data items must be acted on atomically, consider creating an immutable holder class for them.
If there is a need to update the variables inside the immutable object, a new holder object should be created.
4. Delegating Thread Safety, Using Thread Safe Variables -
In the common counter example servlet we only had one counter variable, and we can make the whole servlet thread safe, just my making the counter variable AtomicLong.
I am writing Cache, and sometimes I want to share whole cache to a client, without allowing them to put any key,value pair in cache.
public class CacheHandler {
private final ConcurrentMap cache = new ConcurrentHashMap();
private final Map unmodifiableCache;
public void put(String, Value){
cache.put(String, Value);
}
public Map getCache(){
unmodifiableCache = Collections.unmodifiableMap(cache);
}
}
In the above program I have delegated the thread safety to COncurrentHashMap.
Similarly, we can delegate thread safety to multiple thread safe state variables.
But, if object relates their state variables like operation which involves multiple variables, thread delegation would fail
5. Safe publication of effectively immutable objects. Safe Publication of mutable Objects -
Both the reference to the object and object's state must be made visible to other threads at the same time.
- Initialize an object reference from a static initialize
- Storing reference in a volatile field or AtomicReference
- Storing reference in final of properly constructed object
- Storing reference in a field guarded by lock.
Also, following offer safe publication -
- Placing a key or value in Hashtable, SynchronizedMap, ConcurrentMap.
- Placing an element in Vector, CopyOnWriteArrayList, CopyOnWriteArraySet, synchronizedList, or synchonizedSet
- Placing an element on a BlockingQueue or ConcurrentLinkedQueue.
Note, Safe publication is helpful when object are not going to be modified after publication.
It gaurantees, published(not stale) state is visible to any thread as soon as reference is visible.
If object is effectively immutable(not immutable, but its state wont change), no additional synchronization is required.
Should also know below -
Instance Confinement -
If a non thread safe object is totally confined inside another object. Combining Encapsulation with appropriate locking discipline can enusre otherwise non-thread safe objects are used in thread safe manner. Like making the HashMap as private and synchronizing the put on HashMap.
Java Monitor Pattern -
An object following the Java Monitor Pattern encapsulates all its mutable state and gaurds it with the objects's intrinsic lock.
Lock can be a private object, with benefit that no client code can ever acquire it. Vector and Hashtable work in this way.
When we are writing Java/J2ee programs, we are aware that our program would run inside a multithreaded environment. Our frameworks are multithreaded, servers aree multithreaded, and
JVM is multithreaded. Timer, Servelet, RMI, Swing are all inherently multithreaded, and we should take caution while writing any data, sharing state, and creating data.
Some places where Multi threading is required, apart from the common use
i.e., to fully utilize the hardware, multiple processors. To increase speed, responsiveness of application.
1. Need to start multiple threads rather than making single threaded program more intelligent. If application goes to read from a socket, and no data is available, the thread is blocked. To avoid this problem, single threaded server applications are forced to use Non blocking I/O. NIO is far more complicated and error-prone than synchronous I/O. Multithreading is better approach. If each request is handled in separate thread, the blocking on thread doesn't block other requests.
2. To make application more responsive use multithreading instead of always going for asynchronous. Lot of tasks today are asynchronous, Some are huge and complicated. A complicated, asynchronous workflow can be decomposed into a number of simpler synchronous workflows each running in a separate thread, interacting only with each other at specific synchronization points. We can have a framework. Framework manages request, thread creation, load balancing, and dispatching requests to appropriate handler. Author of handler need not to worry about how many simultaneous requests are handled.
3. User multithreading to avoid delays. One big task, one big transaction, and one big server should not be always preferred. One big task can be broke into separate threads and still be bound in one transaction with no requirement of extra hardware.
Already Thread Safe(Ways we can probably avoid the synchronized block) -
1. Thread Confinement - When an object is confined to a thread, such usage is thread safe, even if the confined object is not thread safe.
Like in pooled JDBC connection objects, the connection object might not be thread safe, but poolis thread safe,
and pool doesn't dispense the same connection to another thread, unless it returns to the pool.
"ThreadLocal" associates a per thread value witha value holding object.
"ThreadLocal" provides get and set accessor methods that maintain a separate copy of value forneach thread that uses it.
Conceptually its like Map
The thread specific valuyes are stored iin the thread itself.
For eg., in an EJB call, the J2EE container associate transaction context with an executing thread for the duration of the EJB call.
This helps container easily determine what transaction is currently running.
2. Stack Confinement - Local Variables are thread safe, local variables can be used to confine objects to a thread.
3. Immutable objects are always thread safe. A properly consturcted(this doesn't escapes), and state can't be modified,
and may be all fields are final. No requirement for safe publication.
Note -> Its good practice to make fields private, unless they need visibility.
Its good practice to make fields final, unless they need to be muatble.
Whenever a group of related data items must be acted on atomically, consider creating an immutable holder class for them.
If there is a need to update the variables inside the immutable object, a new holder object should be created.
4. Delegating Thread Safety, Using Thread Safe Variables -
In the common counter example servlet we only had one counter variable, and we can make the whole servlet thread safe, just my making the counter variable AtomicLong.
I am writing Cache, and sometimes I want to share whole cache to a client, without allowing them to put any key,value pair in cache.
public class CacheHandler {
private final ConcurrentMap
private final Map
public void put(String, Value){
cache.put(String, Value);
}
public Map
unmodifiableCache = Collections.unmodifiableMap(cache);
}
}
In the above program I have delegated the thread safety to COncurrentHashMap.
Similarly, we can delegate thread safety to multiple thread safe state variables.
But, if object relates their state variables like operation which involves multiple variables, thread delegation would fail
5. Safe publication of effectively immutable objects. Safe Publication of mutable Objects -
Both the reference to the object and object's state must be made visible to other threads at the same time.
- Initialize an object reference from a static initialize
- Storing reference in a volatile field or AtomicReference
- Storing reference in final of properly constructed object
- Storing reference in a field guarded by lock.
Also, following offer safe publication -
- Placing a key or value in Hashtable, SynchronizedMap, ConcurrentMap.
- Placing an element in Vector, CopyOnWriteArrayList, CopyOnWriteArraySet, synchronizedList, or synchonizedSet
- Placing an element on a BlockingQueue or ConcurrentLinkedQueue.
Note, Safe publication is helpful when object are not going to be modified after publication.
It gaurantees, published(not stale) state is visible to any thread as soon as reference is visible.
If object is effectively immutable(not immutable, but its state wont change), no additional synchronization is required.
Should also know below -
Instance Confinement -
If a non thread safe object is totally confined inside another object. Combining Encapsulation with appropriate locking discipline can enusre otherwise non-thread safe objects are used in thread safe manner. Like making the HashMap as private and synchronizing the put on HashMap.
Java Monitor Pattern -
An object following the Java Monitor Pattern encapsulates all its mutable state and gaurds it with the objects's intrinsic lock.
Lock can be a private object, with benefit that no client code can ever acquire it. Vector and Hashtable work in this way.
Synchonized -
Every Java object can act as a lock, and these built-in locks are intrinsic locks. Intrinsic locks are re entrant. If Intrinsic locks are not re entrant, many normal looking code would deadlock. A thread would never be able to call another synchronized method from a synchronized method, even if it acquires the lock. Since, acquiring the lock associated with object doesn't prevents other threads from changing the state of object which is used as lock.
So, its better I use the same object whose state I am preventing as lock also, and so we use "this".
Avoid some mistakes -
Every Java object can act as a lock, and these built-in locks are intrinsic locks. Intrinsic locks are re entrant. If Intrinsic locks are not re entrant, many normal looking code would deadlock. A thread would never be able to call another synchronized method from a synchronized method, even if it acquires the lock. Since, acquiring the lock associated with object doesn't prevents other threads from changing the state of object which is used as lock.
So, its better I use the same object whose state I am preventing as lock also, and so we use "this".
Avoid some mistakes -
- Encapsulating all the mutable state within an object, and synchronizing all the code that access the state is bad design. Because it can be confusing, object size can be big, and performance can be low.
- In the absence of synchronization , the Java Memory model permits the compiler to reorder operations and cache values in registers, and permits CPUs to reorder operations and cache values in processor specific caches.
- Never start a new thread from constructor Because generally, when objects creates a thread form constructor, it shares its this reference, And this reference can publish an incompletely constructed object.
- Volatile varibales are good for boolean values, but semantics of volatile are not strong enough to make increment operations
- atomic in multi threaded program.