A method is synchronized when it is marked with the
synchronized
keyword.
When a synchronized method is called, the current thread acquires a lock on the instance referred to by that call,
provided that this instance is not already locked by another thread.
If an instance is already locked by another thread,
then no other thread can acquire a lock on this instance and, therefore, cannot execute any of its synchronized methods.
Each thread that tries to acquire the lock on an already locked instance will be blocked (put in a waiting state) until the instance is unlocked.
As long as the synchronized method is still executing,
the thread holding the lock does not release it — even if it is no longer actively running (e.g., if it is sleeping or waiting for I/O).
class MyClassA {
private String value;
public synchronized void foo() { // synchronized method: locks instance 'this'
setValue(Thread.currentThread().getName() + " : value");
try {
Thread.sleep(1000); // force the current thread to sleep to give the other thread a chance to run
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // restore interrupted status
e.printStackTrace();
}
System.out.println(getValue());
}
private String getValue() {
return value;
}
private void setValue(String value) {
this.value = value;
}
}
public class MainClass {
public static void main(String[] args) {
final MyClassA myClassA = new MyClassA();
Runnable myRunnable1 = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " (start)");
myClassA.foo(); // the current thread will acquire a lock on the instance referred to by "myClassA"
System.out.println(Thread.currentThread().getName() + " (end)");
}
};
Thread myThread1 = new Thread(myRunnable1, "myFirstThread");
Thread myThread2 = new Thread(myRunnable1, "mySecondThread");
myThread1.start();
try {
Thread.sleep(500); // force the "main" thread to sleep to ensure "myFirstThread" starts before "mySecondThread"
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
myThread2.start();
}
}
Output:
myFirstThread (start)
mySecondThread (start)
myFirstThread : value
myFirstThread (end)
mySecondThread : value
mySecondThread (end)
Note that "mySecondThread (start)" prints immediately,
but "mySecondThread" waits for "myFirstThread" to complete the synchronized method before it can execute
foo()
.
This demonstrates that the thread is blocked when trying to acquire the lock, not when starting.