There are a number of ways to achieve asynchronous communication:
- Spring async provides a means to implement concurrency with abstraction over thread handling
- Messaging Queue – ActiveMQ, Kafka, RabitMQ
- Multi-Threading or Concurrency
- Rest-Template(sync) vs the Web-Client (async)
Writing a correct program is hard and writing a correct concurrent program is harder.
There are simply more things can go wrong in concurrent program than a sequential program.
So,Why Use Concurrency? Two reasons to use Concurrency:-
- Concurrency SIMPLIFIES development of complex system by turning COMPLICATED ASYNCHRONOUS CODE into STRAIGHT-LINER code.
- Easiest way to tap the COMPUTING POWER of MULTI-PROCESSOR system.
There are several Other factors too which favors executing multiple programs simultaneously(using multi threading).
- Resource utilization:Programs(sequence of statements) sometimes have to wait for external operation like Input or Output WHILE WAITING(by one thread) can do no USEFUL WORK.it is EFFICIENT to LET ANOTHER PROGRAM run in THAT WAIT TIME.(by another thread)
- Fairness:It is preferable to let them share the computer via finer-grained time slicing than to let one program run to completion and then start another.
- GUI applications for improving the responsiveness of the user interface
- server applications for improving resource utilization and throughput.
Simplified handling of ASYNCHRONOUS events by Multi-Threading:
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.
Example:
Assertion:
A server application that accepts socket connection from multiple remote client MAY be easier to design when EACH CONNECTION is ALLOTTED it’s OWN THREAD and allowed to use SYNCHRONOUS i/o.
Reason:
If application goes to read data when the data is not available, read blocks until some data is available.
In Single Threaded application : the block on read operation not only STALLS the corresponding REQUEST but also PROCESSING of all other
request stalls until the single thread is blocked.
To Avoid this problem single Threaded application forced to use NON-BLOCKING I/O , which is far more error-prone and complicated than SYNCHRONOUS I/O.
However, if each request has its own thread, then blocking does not affect the processing of other requests.
Risks of Thread:
- Safety Hazard:Access to shared variables must be properly coordinated so that threads do not interfere with one another. Fortunately, Java provides synchronization mechanisms to coordinate such access.
- Liveliness failure:A liveliness failure occurs when an activity gets into a state such that it is permanently unable to make forward progress. safety means “nothing bad ever happens”, Liveliness concerns the complementary goal that “something good eventually happens”.Like most concurrency bugs, bugs that cause liveliness failures can be elusive because they depend on the relative timing of events in different threads, and therefore do not always manifest themselves in development or testing.
- Performance hazards:In well designed concurrent applications the use of threads is a net performance gain,But if there are more CONTEXT-SWITCHES it leads to performance over-head i.e a thread being suspended to let another thread run and in-between doing thread tracking task(restoring execution context,CPU time spend in switching than being used in active thread task).
Threads are EVERYWHERE:
“Frameworks introduce concurrency into applications by calling application components from framework threads. Components invariably access application state, thus requiring that all code paths accessing that state be thread-safe.”
Following facilities causes Application-CODE not called from ‘thread managed by application’ but from framework threads:
- Timer: Timer is convenient mechanisms to run the TASKS at later time periodically(once or repeatedly).The introduction of a Timer can complicate an otherwise sequential program, because TimerTasks are executed in a thread managed by the Timer, not the application. If a TimerTask accesses data that is also accessed by other application threads, then not only must the TimerTask do so in a thread-safe manner, but so must any other classes that access that data.The easiest way to achieve this is to ensure that objects accessed by the Timer-Task are themselves thread-safe, thus encapsulating the thread safety within the shared objects.
- Servlets and JavaServer Pages (JSPs):The servlets framework handle all dispatching requests from remote HTTP clients, to the appropriate servlet or JSP(a component of application logic) and in high-volume web sites, multiple clients may require the services of the same servlet at once.In other words, servlets need to be thread-safe.
- Remote Method Invocation:RMI lets you invoke methods on objects running in another JVM.When the RMI code calls your remote object, in what thread does that call happen? You don’t know, but it’s definitely not in a thread you created—your object gets called in a thread managed by RMI. RMI create many threads. So,A remote object must guard against thread safety hazards.
- Swing and AWT: When the user performs a UI action, an event handler is called in the event thread to perform whatever operation the user requested. If the handler needs to access application state that is also accessed from other threads (such as a document being edited), then the event handler, along with any other code that accesses that state, must do so in a thread-safe manner.
Best Pacctices – Src – Linkedin
- [1.] Always design with concurrency in mind, considering thread safety and potential race conditions from the start.
- [2.] Understand the Java memory model and the guarantees it provides for visibility and ordering of shared variables.
- [3.] Use synchronization mechanisms, such as synchronized blocks and methods, to ensure thread safety when accessing shared data.
- [4.] Minimize the scope of synchronized blocks to reduce contention and improve performance.
- [5.] Use volatile keyword for simple flags or variables that require atomic updates without mutual exclusion.
- [6.] Prefer higher-level concurrency utilities, such as java.util.concurrent classes, over low-level thread manipulation.
- [7.] Utilize concurrent collections, such as ConcurrentHashMap and ConcurrentLinkedQueue, for efficient and thread-safe data sharing.
- [8.] Be cautious when sharing mutable objects among threads and consider using immutable objects or thread-local variables instead.
- [9.] Understand the happens-before relationship to reason about the visibility and ordering of operations in a concurrent program.
- [10.] Use atomic variables, such as AtomicInteger and AtomicReference, to perform atomic operations without explicit synchronization.
- [11.] Be aware of the potential pitfalls of double-checked locking and prefer lazy initialization techniques like using the Initialization-on-Demand Holder idiom.
- [12.] Use thread-local variables when you need to maintain thread-specific state without explicit synchronization.
- [13.] Beware of the risks associated with publishing shared objects prematurely, and ensure proper synchronization or immutability before sharing them.
- [14.] Employ thread pools and the Executor framework for efficient thread management and task execution.
- [15.] Tune thread pool configurations, such as the number of threads and the work queue size, based on the characteristics of your application.
- [16.] Consider the ExecutorCompletionService to process task results as they become available, improving responsiveness and resource utilization.
- [17.] Be cautious when interrupting threads and handle InterruptedException properly to ensure graceful termination and cleanup.
- [18.] Avoid unnecessary synchronization by using thread-safe libraries and designing thread-safe code from the ground up.
- [19.] Profile and measure the performance of your concurrent applications to identify bottlenecks and areas for optimization.
- [20.] Stay updated with the latest advancements in Java concurrency.