Java multithreading synchronized method with two threads
Asked Answered
G

4

0

I have a very simple code but unable to understand.

    public class Test extends Thread {
    
        public synchronized void testPrint() {
            System.out.println("I am sleeping..."
                    + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
                System.out.println("I am done sleeping..."
                        + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public void run() {
            Test t = new Test();
            t.testPrint();
    
            System.out.println("I am out..." + Thread.currentThread().getName());
        }
    
        public static void main(String[] args) {
            Test t1 = new Test();
            Test t2 = new Test();
    
            t1.start();
            t2.start();
    
        }
    }

Here is my questions

When two threads executing Test t = new Test(), does this create two different objects with same name? What happens at this line with multiple threads?

I am getting below result,

I am sleeping...Thread-0

I am sleeping...Thread-1

I am done sleeping...Thread-0

I am out...Thread-0

I am done sleeping...Thread-1

I am out...Thread-1


From the output, It definitely means that there are two objects created, that is why both the threads could enter in the sync method. hope my understanding is correct ? How system maintains these two objects?

Genovevagenre answered 1/11, 2013 at 5:28 Comment(1)
synchronized does not synchronize a method, it synchronizes the object. In your case the two threads have their own object and no shared data so there is no reason for them to interact. Yes new creates a new object.Kehr
L
1

When you run Test t = new Test() jvm create new object on heap and put variable t with link to that object on stack of current thread.
When you run that code in two or more different threads each of them have own stack, so each of them create his own variable t and object Test

Landowska answered 1/11, 2013 at 5:34 Comment(4)
Here two threads will enter in run, will this create two objects or one ? if it's creating two objects in two respective threads, How can I use these two objects in subsequent code ? i.e. both the objects have same name 't' ! Or the scope is only in those threads only ? If threads share the memory, these objects should be accessible for others and main thread .. how can I use it then? If it's creating only one object with 2 references then both thread should not enter in the method at same time.. right ? but output shows otherwise.Genovevagenre
there are two objects, but there is no link to them from other code. In java you cannot access memory directly - you should save link to object in variable or property. When you save link to variable it cannot be accessed from other threads, when in property - it can be accessed.Landowska
Ok Thanks I think I got it. Only thing is if I am using 't' object in the code in that case which object it will refer ? created by Thread 1 or 2 ? And how would I know which ones created, as the state of the objects might be different. Is this code a flaw ?Genovevagenre
In your code you using object that created in current thread. It's not flaw by itself, it depends on your targetLandowska
S
2

You are creating two different object which will have two different monitors on which lock will be acquired. As both thread work on different objects synchronization does not come into picture.

You can try

public class Test extends Thread {

Object obj;

public Test(Object obj){
    this.obj = obj;
}

public synchronized void testPrint() {
    System.out.println("I am sleeping..."
            + Thread.currentThread().getName());
    try {
        Thread.sleep(3000);
        System.out.println("I am done sleeping..."
                + Thread.currentThread().getName());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

public void run() {
    ((Test)obj).testPrint();
    System.out.println("I am out..." + Thread.currentThread().getName());
}

public static void main(String[] args) {

    Object obj = new Test(null);

    Test t1 = new Test(obj);
    Test t2 = new Test(obj);

    t1.start();
    t2.start();

}
}

and the output is

I am sleeping...Thread-1
I am done sleeping...Thread-1
I am out...Thread-1
I am sleeping...Thread-2
I am done sleeping...Thread-2
I am out...Thread-2

as expected.

Smoke answered 1/11, 2013 at 5:30 Comment(0)
F
2

With your current approach, you ensure that for each instance of Test the method testPrint() can not run concurrently. It all depends on what you want to do. I assume that you want to protect the testPrint() method from running in multiple threads concurrently, with multiple instances of Test.

Currently you use the synchronized keyword directly on the method. This results in using the object itself (an instance of Test) being used for synchronization.

You should synchronize on another object that is shared between the instances of Test(you could for example make the lock object static).

Also note, that it is general a better idea to implement only the Runnable interface and then pass the implementation to the thread. Plus, you don't have to create a new instance of Test every time you run (i don't see the purpose of that), i commented that out.

public class Test extends Thread {
  // could also use a static monitor instead.
  // private static final Object monitor = new Object();
  private final Object monitor;

  public Test(final Object monitor) {
    this.monitor = monitor;
  }

  public void testPrint() {
    synchronized (monitor) {
      System.out.println("I am sleeping..." + Thread.currentThread().getName());
      try {
        Thread.sleep(3000);
        System.out.println("I am done sleeping..." + Thread.currentThread().getName());
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  public void run() {
    //Test t = new Test(monitor);
    //t.testPrint();
    testPrint();
    System.out.println("I am out..." + Thread.currentThread().getName());
  }

  public static void main(String[] args) {
    // synchronization will happen on this object.
    final Object monitor = new Object();

    Test t1 = new Test(monitor);
    Test t2 = new Test(monitor);

    t1.start();
    t2.start();

  }
}
Friendly answered 1/11, 2013 at 8:34 Comment(0)
L
1

When you run Test t = new Test() jvm create new object on heap and put variable t with link to that object on stack of current thread.
When you run that code in two or more different threads each of them have own stack, so each of them create his own variable t and object Test

Landowska answered 1/11, 2013 at 5:34 Comment(4)
Here two threads will enter in run, will this create two objects or one ? if it's creating two objects in two respective threads, How can I use these two objects in subsequent code ? i.e. both the objects have same name 't' ! Or the scope is only in those threads only ? If threads share the memory, these objects should be accessible for others and main thread .. how can I use it then? If it's creating only one object with 2 references then both thread should not enter in the method at same time.. right ? but output shows otherwise.Genovevagenre
there are two objects, but there is no link to them from other code. In java you cannot access memory directly - you should save link to object in variable or property. When you save link to variable it cannot be accessed from other threads, when in property - it can be accessed.Landowska
Ok Thanks I think I got it. Only thing is if I am using 't' object in the code in that case which object it will refer ? created by Thread 1 or 2 ? And how would I know which ones created, as the state of the objects might be different. Is this code a flaw ?Genovevagenre
In your code you using object that created in current thread. It's not flaw by itself, it depends on your targetLandowska
F
0
Test t = new Test()

This will create a object in the heap and the reference will be placed in the stack.

Here in your example you dont need the synchronized method at all because you are not sharing the instance among different thread.

Fateful answered 1/11, 2013 at 5:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.