Let's take a look at this example:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Resource { | |
private Object veryImportantObject = new Object(); | |
private final Object mutex = new Object(); | |
public synchronized Object getVeryImportantObject() { | |
System.out.println("Getting object"); | |
return veryImportantObject; | |
} | |
public Object getVeryImportantObjectWithMutex() { | |
synchronized(mutex) { | |
System.out.println("Getting object with mutex"); | |
return veryImportantObject; | |
} | |
} | |
} |
getVeryImportantObject() has synchronized modifier.
getVeryImportantObjectWithMutex() uses synchronized block on private object.
We also have an evil class:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Cheater { | |
private final Resource resource; | |
public Cheater(Resource resource) { | |
this.resource = resource; | |
} | |
public void blockResource() { | |
synchronized(resource) { | |
System.out.println("I'm blocking resource"); | |
while(true) { | |
try { | |
Thread.sleep(10); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
} | |
} |
The class that glues it together:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Pitfall { | |
public static void main(String[] args) throws Exception { | |
final Resource resource = new Resource(); | |
Executors.newSingleThreadExecutor().submit(new Runnable() { | |
@Override | |
public void run() { | |
new Cheater(resource).blockResource(); | |
} | |
}); | |
Thread.sleep(1000); | |
Executors.newSingleThreadExecutor().submit(new Runnable() { | |
@Override | |
public void run() { | |
resource.getVeryImportantObject(); | |
} | |
}); | |
Executors.newSingleThreadExecutor().submit(new Runnable() { | |
@Override | |
public void run() { | |
resource.getVeryImportantObjectWithMutex(); | |
} | |
}); | |
} | |
} |
Project Lombok provides an interesting way of not getting into this trap (http://projectlombok.org/features/Synchronized.html)