Last Updated on August 20, 2023 by KnownSense
Synchronization is the coordination of two or more tasks to get the desired results. We have two kinds of synchronization:
- Control synchronization: When, for example, one task depends on the end of another task, the second task can’t start before the first has finished
- Data access synchronization: When two or more tasks have access to a shared variable and only one of the tasks can access the variable at any given time.
synchronization helps you avoid some errors you can have with concurrent tasks but it introduces some overhead. You have to calculate very carefully the number of tasks, which can be performed independently without intercommunication in your parallel algorithm. It’s the granularity of your concurrent algorithm.
Granularity is of 2 type:
coarse-grained granularity– big tasks with low intercommunication
fine-grained granularity– small tasks with high intercommunication
Synchronization mechanisms
The Java concurrency API includes different synchronization mechanisms that allow you to:
• Define a critical section to access a shared resource
• Synchronize different tasks in a common point
The following mechanisms are considered to be the most important synchronization mechanisms:
- The synchronized keyword: The synchronized keyword allows you to define a critical section in a block of code or in an entire method.
- The Lock interface: Lock provides a more flexible synchronization operation than the synchronized keyword. There are different kinds of Locks: ReentrantLock, to implement a Lock that can be associated with a condition; ReentrantReadWriteLock, which separates read and write operations; and StampedLock, a new feature of Java 8 that includes three modes for controlling read/write access.
- The Semaphore class: The class that implements the classical semaphore to implement synchronization. Java supports binary and general semaphores.
- The CountDownLatch class: A class that allows a task to wait for the finalization of multiple operations.
- The CyclicBarrier class: A class that allows the synchronization of multiple threads in a common point.
- The Phaser class: A class that allows you to control the execution of tasks divided into phases. None of the tasks advance to the next phase until all of the tasks have finished the current phase.
Other Synchronization Mechanisms and Frameworks
The Java programming language has a very rich concurrency API that helps in threads Synchronization. It contains classes to manage the basic elements of concurrency, such as Thread, Lock, and Semaphore, and classes that implement very high-level synchronization mechanisms, such as the executor framework or the new parallel Stream API.
- Executors : The executor framework is a mechanism that allows you to separate thread creation and management for the implementation of concurrent tasks. You don’t have to worry about the creation and management of threads, only about creating tasks and sending them to the executor.
- The Fork/Join framework: The Fork/Join framework defines a special kind of executor specialized in the resolution of problems with the divide and conquer technique.
- Parallel streams: Streams and Lambda expressions are the two most important new features of the Java 8 version. Streams have been added as a method in the Collection interface and other data sources and allow processing all elements of a data structure, generating new structures, filtering data and implementing algorithms using the map and reduce technique.
- Concurrent data structures: Normal data structures of the Java API (ArrayList, Hashtable, and so on) are not ready to work in a concurrent application unless you use an external synchronization mechanism. If you use it, you will be adding a lot of extra computing time to your application. If you don’t use it, it’s probable that you will have race conditions in your application. If you modify them from several threads and a race condition occurs, you may experience various exceptions thrown (such as, ConcurrentModificationException and ArrayIndexOutOfBoundsException), there may be silent data loss or your program may even stuck in an endless loop. The Java concurrency API includes a lot of data structures that can be used in concurrent applications without risk.