Java also introduced atomic arrays that provide atomic operations for arrays of integer or long numbers. (link)
This operation is called Compare and Set . (link)
To avoid these problems, Java introduced the atomic variables. When a thread is doing an operation with an atomic variable, if other threads want to do an operation with the same variable, the implementation of the class includes a mechanism to check that the operation is done in one step. (link)
First, check if the storage is full or not. If it's full, it calls the wait() method until the storage has empty space. At the end of the method, we call the notifyAll() method to wake up all the threads that are sleeping in the wait() method. (link)
A classic problem in concurrent programming is the producer-consumer problem. We have a data buffer, one or more producers of data that save it in the buffer and one or more consumers of data that take it from the buffer. (link)
In other words, every method declared with the synchronized keyword is a critical section and Java only allows the execution of one of the critical sections of an object. (link)
Vikram: [If an object has two synchronized methods, and one thread is accessing one of those synchronized methods, another thread cannot access the other synchronized method. It's as if all synchronized methods within a object form a critical section that only one thread can access at time. However, static synchronized method can still be accessed by other threads. ]
The solution for these problems comes with the concept of critical section . A critical section is a block of code that accesses a shared resource and can't be executed by more than one thread at the same time. (link)
The Lock interfaces allow a separation of read and write operations having multiple readers and only one modifier. (link)
Vikram: [Don't see why this can't be done with two separate synchronized objects]
One of the new functionalities is implemented by the tryLock() method. This method tries to get the control of the lock and if it can't, because it's used by other thread, it returns the lock. With the synchronized keyword, when a thread (A) tries to execute a synchronized block of code, if there is another thread (B) executing it, the thread (A) is suspended until the thread (B) finishes the execution of the synchronized block. (link)
Vikram: [When using synchronized, threads wait, whereas with tryLock(), thread returns]