With the following code, if a thread calls LoggingWidget.doSomething(),
what is the order of lock acquisition that the thread has to go through?
(i.e. does it get the Lock on LoggingWidget first, and then gets the lock on Widget ? )
public class Widget {
public synchronized void doSomething() {
}
}
public class LoggingWidget extends Widget {
public synchronized void doSomething() {
System.out.println(toString() + ": calling doSomething");
super.doSomething();
}
}
The lock in this case is on this so there is only one lock, that being the instance. If there are more than one instance, each has an entirely separate lock regardless of whether it is a Widget or a LoggingWidget.
Let me put it another way. Your code is semantically equivalent to:
public class Widget {
public void doSomething() {
synchronized (this) {
// do stuff
}
}
}
public class LoggingWidget extends Widget {
public void doSomething() {
synchronized (this) {
System.out.println(toString() + ": calling doSomething");
super.doSomething();
}
}
}
Only one of these methods is called so there's only one lock.
In Java, they're caleld monitors and are per object. In your example, there is only one monitor.
There is only one lock bcoz there is only one object, but if the sub-class object's doSomething() method is called, the same lock is acquired twice. In JVM, the owner(thread) is same but it sets the acquisition count to two. The acquisition count is decremented each time when the owning thread exists the synchronized block. So here it would be decremented twice down to zero when the lock is finally released, one for each synchronized block.
If you want to ensure you get the correct lock of type LoggingWidget and not Widget you can do this:
public class LoggingWidget extends Widget {
private final Object readLock = new Object();
public void doSomething() {
synchronized (readLock) {
System.out.println(toString() + ": calling doSomething");
super.doSomething();
}
}
}
Or if you use Lombok you can just write
public class LoggingWidget extends Widget {
#Synchronized("readLock")
public void doSomething() {
System.out.println(toString() + ": calling doSomething");
super.doSomething();
}
}
Related
I have added comments in code to explain from where deadlock is occurring.
Basically, There are two threads. Each thread acquires lock on an Manager object and then go for acquiring lock on static resource, which is a map of all the Manager objects in the application.Both thread calls get() on map.
Manager class has overridden equals() method. equals() further calls some synchronized method of Manager class. So a get() on map will need object level lock on each object in the map one by one until key matches because equals is overridden.
I can only change the code in sub classes(Sub1 and Sub2) and avoid the deadlock, as I don't have access to other classes.
Edit: I don't have access to syncMap. The code in 'synchronized' block executes in third party code whose API I call to.
Can I avoid this by acquiring lock in finally on Manager, rather than before try block ?!
public class Parent{
protected Manager manager;
}
public class Global{
private static final Map syncMap = Collections.synchronizedMap(new HashMap());
//syncMap contains all the objects of Manager in the application
}
class Manager{
public boolean equals(Object o){
Manager obj = (Manager)o;
return obj.getURL().equals(getURL());
}
public final synchronized String getURL(){
return msettings.getDBURL(); //msettings is a global variable
}
}
//Thread-1 is executing someMethod() of this class
class Sub1 extends Parent{
Global global;
//consider manager and Global object are not null
public void someMethod()
{
synchronized(manager){// Thread-1 succesfully takes object level lock on a manager object, say Manager01
try{
global.syncMap.get(manager);
// Thread-1 Succesfully takes class level lock on syncMap
// get() calls equals() for each object in syncMap.
//equals() need object lock on each Manager Object in map as it further calls synchronized getURL()
// But on one manager Object(Manager02) Thread-2 has already acquired lock and is waiting for lock on syncMap which this thread-1 holds
}
finally{
manager.releaseConnection();
}
}
}
}
//Thread-2 is executing otherMethod() of this class
class Sub2 extends Parent{
public void otherMethod()
{
synchronized(manager){// this takes a lock on manager(Manager02)
try{
global.syncMap.get(manager);
// this is blocked as syncMap is aquired by thread-1
}
finally{
manager.releaseConnection();
}
}
}
}
After new portion of information I don't see another solution except of turning all processing into serial-style. So you can put all manager-associated API calls in one synchronized method of some wrapping class and use this wrapper as a single entry-point for third-party API.
class BrutalWrapper {
public synchronized void doIt(Manager manager)
{
try{
global.syncMap.get(manager);
}
finally{
manager.releaseConnection();
}
}
}
class Sub1 extends Parent{
BrutalWrapper brutal;
public void someMethod()
{
brutal.doIt(manager);
}
}
class Sub2 extends Parent{
BrutalWrapper brutal;
public void someMethod()
{
brutal.doIt(manager);
}
}
First of all, you really should try to eliminate the need for synchronization in the equals method. It will cause more trouble than it solves so if a redesign is possible then I think thats the best way.
However, if you restructure the code a bit and move the global.syncMap.get(manager) to before the synchronization block it would not generate a deadlock
public Class Parent{
protected Manager manager;
}
class Global{
private static final Map syncMap = Collections.synchronizedMap(new HashMap());
//syncMap contains all the objects of Manager in the application
}
class Manager{
public boolean equals(Object o){
Manager obj = (Manager)o;
return obj.getURL().equals(getURL());
}
public final synchronized String getURL(){
return msettings.getDBURL(); //msettings is a global variable
}
}
//Thread-1 is executing someMethod() of this class
class Sub1 extends Parent{
Global global;
//consider manager and Global object are not null
public void someMethod()
{
try {
global.syncMap.get(manager);
synchronized(manager){
}
}
finally{
manager.releaseConnection();
}
}
}
//Thread-2 is executing otherMethod() of this class
class Sub2 extends Parent{
public void otherMethod()
{
try {
global.syncMap.get(manager);
synchronized(manager){
}
}
finally{
manager.releaseConnection();
}
}
}
UPDATE Alternative synchronization over Global.class, could probably use instance variable global also instead of Global.class
UPDATE Changed synchronization to be over Manager.class instead of Global.class.
class Sub1 extends Parent
{
Global global;
public void someMethod()
{
synchronized (Manager.class) {
try {
global.syncMap.get(manager);
}
finally {
manager.releaseConnection();
}
}
}
}
class Sub2 extends Parent
{
Global global;
public void otherMethod()
{
synchronized (Manager.class) {
try {
global.syncMap.get(manager);
}
finally {
manager.releaseConnection();
}
}
}
}
I have a class like this one:
public class IClass{
public void draw(){...}; //is called periodically by the rendering thread
public void foo(){...}; //is called asynchronously from another Thread(it could be an onTouchEvent() method for example)
}
I want the foo() method to wait until the draw method is finished and vice versa. How can I do this in Java?
regards
Make the methods synchronized.
public synchronized void draw() { System.out.println("draw"); }
public synchronized void foo() { System.out.println("foo"); }
Or synchronize on the same object.
private static final Object syncObj = new Object();
public void draw() {
synchronized (syncObj) {
System.out.println("draw");
}
}
public void foo() {
synchronized (syncObj) {
System.out.println("foo");
}
}
Putting synchronized on a method means the thread has to acquire the lock on the object instance before entering that method, so if you have two different methods marked synchronized the threads entering them will be contending for the same lock, and once one thread gets the lock all other threads are shut out of all methods that synchronize on that same lock. So in order for the two methods to run concurrently they would have to use different locks, like this:
public class IClass {
private final Object lockDraw = new Object();
private final Object lockFoo = new Object();
public void draw() {
synchronized(lockDraw) {
//method draw
}
}
public void foo() {
synchronized(lockFoo) {
//method foo
}
}
}
Both methods lock the same monitor. Therefore, you can't simultaneously execute them on the same object from different threads (one of the two methods will block until the other is finished).
public synchronized int getCountOne() {
return count++;
}
Like in above code synchronizing on the method is functionally equivalent to having a synchronized (this) block around the body of the method. The object "this" doesn't become locked, rather the object "this" is used as the mutex and the body is prevented from executing concurrently with other code sections also synchronized on "this."
On similar grounds what is used as a mutex when we acquire a class level lock.As in if we have a function
public static synchronized int getCountTwo() {
return count++;
}
obviously two threads can simultaneously obtain locks on getCountOne(object level lock) and getCountTwo(class level lock). So as getCountOne is analogous to
public int getCountOne() {
synchronized(this) {
return count++;
}
}
is there an equivalent of getCountTwo? If no what criteria is used to obtain a Class level lock?
On similar grounds what is used as a mutex when we acquire a class level lock
The class object itself will be used as mutex. The equivalent synchronized block for your static synchronized method will look like:
public static int getCountTwo() {
synchronized(ClassName.class) {
return count++;
}
}
ClassName is the name of the class containing that method.
See JLS Section §8.4.3.6:
A synchronized method acquires a monitor (§17.1) before it executes.
For a class (static) method, the monitor associated with the Class
object for the method's class is used.
For an instance method, the monitor associated with this (the object
for which the method was invoked) is used.
Emphasis mine.
Object level locking:
Object level locking is mechanism when you want to synchronize a non-static method or non-static code block such that only one thread will be able to execute the code block on given instance of the class. This should always be done to make instance level data thread safe. This can be done as below :
public class DemoClass
{
public synchronized void demoMethod(){}
}
or
public class DemoClass
{
public void demoMethod(){
synchronized (this)
{
//other thread safe code
}
}
}
or
public class DemoClass
{
private final Object lock = new Object();
public void demoMethod(){
synchronized (lock)
{
//other thread safe code
}
}
Class level locking:
Class level locking prevents multiple threads to enter in synchronized block in any of all available instances on runtime. This means if in runtime there are 100 instances of DemoClass, then only one thread will be able to execute demoMethod() in any one of instance at a time, and all other instances will be locked for other threads. This should always be done to make static data thread safe.
public class DemoClass
{
public synchronized static void demoMethod(){}
}
or
public class DemoClass
{
public void demoMethod(){
synchronized (DemoClass.class)
{
//other thread safe code
}
}
}
or
public class DemoClass
{
private final static Object lock = new Object();
public void demoMethod(){
synchronized (lock)
{
//other thread safe code
}
}
}
What if a synchronized method calls another synchronized method (in another class), which does wait(). Will the lock be released in the first synchronized method as well, although being in another class?
E.g.
public class A {
private B b;
public A(B b) {
this.b = b;
}
public synchronized String a() {
return b.b();
}
}
public class B {
public synchronized String b() {
while (!someCondition) wait();
return "Success!";
}
}
So my question is, will it be possible to enter another synchronized method in A during the time someCondition = false? Or does wait() just make it possible to enter other synchronized methods in B while an attempt to enter another synchronized method in A will fail until a() returns?
No. While invoking a and subsequently b, no other method can enter neither a or b (or any other synchronized method of classes A or B). b.wait() however releases the lock on all synchronized methods on B since
public synchronized String b()
is essentially equivalent to
public String b() {
synchronized(this) {
..
}
}
I have a quick question about Java synchronization.
Please assume the following code:
public class Test {
private String address;
private int age;
public synchronized setAddress(String a) {
address = a;
}
public synchronized setAge(int a) {
age = a;
}
public synchronized void start() {
...
listener = new Thread(new Runnable(){
public void run() {
...
setAge(10);
...
synchronized(Test.this) {
address = null;
}
}
}
}
}
I am a little bit unsure about Java synchronization when synchronized method or synchronized block is called inside another thread.
Assume the thread running class Test as A, and
the listener thread B.
Then if I execute the code above, does it guarantee that synchronized method calls and synchronized block are synchronized with the A (the thread running Test class) ?
Thank you for reading.
No,
The synchronized methods are locking the Test instance, while the synchronized block is locking the Test class object.
See Java synchronized static methods: lock on object or class and Java Synchronized Block for .class