Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A question on Java multi-threading

Assume the following class

public class TestObject{
    public void synchronized method1(){
        //some 1000 lines of code
    }

    public void method2(){
        //some 1000 lines of code
    }
}

Let's assume there are two threads accessing the same instance of TestObject class, let's call them t1 and t2. I want to know what will happen in the following scenario.

  1. When t1 is in midway of accessing method1(). Now t2 is trying to access method2().
  2. When t1 is in midway of accessing method2(). Now t2 is trying to access method1().

My understanding is that for the first question, the thread t2 will not be given permission as the object will be locked by t1. For the second question, the thread t2 will be granted access and takes lock on the object and will stall t1 from execution. But my assumption was wrong. Can anyone explain this?

Thanks

like image 773
bragboy Avatar asked Oct 29 '10 11:10

bragboy


2 Answers

Only the method with the keyword synchronized holds a lock for this object when a thread is running in that method.
Had both method 1 and method 2 been declared as synchronized, one thread would block the other even though they are trying to run different methods.
In your example only 1 method is blocking by an implicit lock.
As a result t1 and t2 can be running concurrently in method 1 and method 2 (or vice versa).
Only when trying to access method 1, a t1 or t2 would block if the lock has already been acquired

like image 106
Cratylus Avatar answered Sep 19 '22 02:09

Cratylus


When you declare a method to be synchronized, e.g.:

public synchronized void foo() {
    // Do something
}

the compiler treats it as though you had written this:

public void foo() {
    synchronized (this) {
        // Do something
    }
}

In your example you have one synchronized method and one non-synchronized. This means that only access to method1 will be locked. Locking checks are only done on entry to a synchronized block, so calling method2 will not trigger any locking.

To answer your two questions, then, in both cases the two threads will be allowed to proceed because they are not trying to obtain a lock on the same object. If you declare method2 to be synchronized (or manually add a synchronized (this) block) then one thread will be forced to wait for the other.

Remember: synchronizing on an object does not prevent other threads calling methods on that object. It only prevents another thread entering a synchronized block with the same lock object.

Incidentally, it's often better to have an internal lock object rather than declaring methods to be synchronized, e.g.

class Foo {
    private final Object LOCK = new Object();
    public void doSomething() {
        synchronized (LOCK) {
            // Whatever
        }
    }
}

Otherwise I can break your thread-safety by doing this:

class MessEverythingUp {
    public MessEverythingUp(Foo foo) {
        synchronized (foo) {
            while (true) {
                System.out.println("Pwnd ur thread safety");
            }
        }
    }
}

Since I'm locking the instance of foo, your synchronized methods (with their implicit "synchronized (this)") will not be able to obtain a lock and will block forever. Most importantly, you cannot prevent this because I can synchronize on whatever object I like. Obviously the example is extreme but you can get nasty, subtle deadlock bugs if you're not careful about this sort of thing.

like image 22
Cameron Skinner Avatar answered Sep 18 '22 02:09

Cameron Skinner