Lab 6 - Structures and Atomic Operations in Java
ποΈ Semaphores (continued)
In the previous lab, we saw how a semaphore is a generalization of a mutex. A semaphore initialized with 1 can be used as a lock because only one thread can access the critical section at a time. However, a semaphore can have much more complex uses since it can take various values, both negative and positive.
ποΈ AtomicInteger Class
The AtomicInteger class can be thought of as an atomic implementation of an Integer because it holds an integer value and provides atomic operations on it. It can be initialized with a value or left uninitialized, with the default value being 0.
ποΈ ConcurrentHashMap Class
ConcurrentHashMap is a class that provides the same functionalities as a HashTable (not HashMap, as it does not allow using null as a key or value).
ποΈ BlockingQueue Class
The BlockingQueue interface extends the Queue interface, and the classes that implement it are suitable for parallel programs where concurrency issues can arise. Among these, the most relevant ones are ArrayBlockingQueue, LinkedBlockingQueue, and PriorityBlockingQueue. All of them simulate a FIFO (queue) structure with thread-safe operations.
ποΈ Collections.synchronized Methods
If we want to work with classic collections like ArrayList and ensure synchronized operations, we can instantiate them using:
ποΈ Concurrent Trees
When working with more complex data structures, we need to ensure synchronized access to them, while also considering the overall implementation efficiency. To illustrate this with a concrete example, let's assume we have a binary tree. When inserting an element into such a tree, we first check if the node where we want to insert has a left child. If it doesn't, the new child node will be inserted on the left; otherwise, it will be inserted on the right:
ποΈ Exercises
1. Starting from the lab skeleton, solve the synchronization problem in the multipleProducersMultipleConsumers package using ArrayBlockingQueue.