As pointed out in other answers: By synchronizing on this
, you are exposing the object hat you are locking on.
But to point out again why this may be a problem: It can cause deadlocks. Imagine, for example, these two methods being executed by two different threads:
private final Object localMonitor = new Object();
private final Pool pool = new Pool();
void methodA()
{
synchronized (localMonitor)
{
pool.releaseObject(null);
}
}
void methodB()
{
synchronized (pool)
{
synchronized (localMonitor)
{
System.out.println("Performing some work...");
}
}
}
The first thread will synchronize on the localMonitor
and then try to call the method from the Pool
class.
The second thread will synchronize on the pool
instance, and then try to synchronize on the localMonitor
.
For itself, this code is "valid". This would actually be fine. Unless the method from the Pool
class is synchronized as well. Then, the threads will run into a deadlock. Such a situation can be avoided by using a dedicated syncObject
.
Illustrated here again, as a runnable example: Just change the object to be synchronized
on by switching the commented lines to see the difference.
class Pool
{
private final Object syncObject = new Object();
public void releaseObject(Object o)
{
//synchronized (syncObject) // <----------- This will work
synchronized (this) // // <----------- This will cause a deadlock
{
System.out.println("Modify pool");
}
}
}
class SimpleSynchronizeExample
{
public static void main(String[] args)
{
SimpleSynchronizeExample s = new SimpleSynchronizeExample();
s.start();
}
private final Object localMonitor = new Object();
private final Pool pool = new Pool();
void methodA()
{
synchronized (localMonitor)
{
try { Thread.sleep(100); } catch (Exception e) {}
pool.releaseObject(null);
}
}
void methodB()
{
synchronized (pool)
{
try { Thread.sleep(100); } catch (Exception e) {}
synchronized (localMonitor)
{
System.out.println("Performing some work...");
}
}
}
private void start()
{
Thread tA = new Thread(new Runnable()
{
@Override
public void run()
{
methodA();
}
});
Thread tB = new Thread(new Runnable()
{
@Override
public void run()
{
methodB();
}
});
tA.start();
tB.start();
try
{
tA.join();
tB.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("Done");
}
}