Java Synchronized Locking Mechanism
In Java, synchronized is an intrinsic object lock that can be used to protect concurrent access to shared resources. It can modify methods and code blocks; its function is to allow only one thread to enter the method or code block modified by synchronized at a time, while other threads must wait for the lock to be released before accessing the method or code block.
synchronized has the following characteristics:
- Reentrancy: If a thread has already acquired the lock of an object, it can acquire the lock of that object again.
- Visibility: Before a thread releases the lock, its modifications to shared variables are visible to other threads.
- Atomicity:
synchronizedensures that operations on shared variables are atomic; that is, while one thread is modifying a shared variable, other threads cannot access that variable, thereby avoiding data races and consistency issues.
There are several points to note when using synchronized:
- It is generally recommended to use
synchronizedto protect access to shared resources rather than all the code within a method, in order to reduce lock contention and improve concurrent performance. synchronizedcan be used on both static methods and instance methods. For static methods, the class'sClassobject is locked; for instance methods, the instance object is locked.synchronizedcan be used on code blocks by specifying a lock object in the form ofsynchronized(lock_object). The lock object can be any Java object, but it must be ensured that all threads use the same lock object.- When using
synchronized, one should strive to minimize the granularity of the lock, i.e., usesynchronizedonly within necessary code blocks, to avoid issues such as deadlocks and starvation.
In summary, synchronized is an intrinsic lock in Java used to protect shared resources, characterized by reentrancy, visibility, and atomicity. When using synchronized, attention should be paid to the granularity of the lock and lock contention to ensure data consistency and correctness in a multi-threaded environment.
Examples
Below is an example using synchronized to protect concurrent access to shared resources:
public class Counter {
private int count;
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public synchronized int getCount() {
return count;
}
}
In this example, the Counter class has a shared count variable. The increment() method and decrement() method perform increment and decrement operations on the count variable, respectively, while the getCount() method returns the current value of the count variable. Since the count variable is a shared resource, data races and consistency issues may occur in a multi-threaded environment; therefore, the synchronized keyword must be used to protect its concurrent access.
In this example, the increment(), decrement(), and getCount() methods all use the synchronized keyword, ensuring that only one thread can access these methods at a time. Other threads must wait for the lock to be released before accessing these methods, thereby guaranteeing the thread safety and correctness of concurrent access to the count variable.
It should be noted that in this example, the entire method is modified by the synchronized keyword. While this ensures the thread safety of the method, it also causes lock contention and performance degradation. If only partial code blocks need protection for concurrent access, the synchronized code block approach can be used to reduce the granularity of the lock and improve concurrent performance.