What does it mean to have a synchronized block on a different monitor than the 'this' instance?

I have the following piece of code. It has two objects: MultiThreadingTest and ThreadB object. When we say synchronized (b) , what does it mean? Can the "main" thread acquire a lock on b before ThreadB exits? I cannot understand the meaning of the monitoring object in the synchronized block.

 package threads;

    class MultiThreadingTest
    {
        public static void main(String[] args)
        {
            ThreadB b = new ThreadB();
            b.setName("Thread B");
            b.start();
            synchronized(b)     
            {
                System.out.println("Current thread : "+ Thread.currentThread().getName());          
                try
                {
                    System.out.println("Waiting for b to complete...");
                    b.wait();
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                }   
                System.out.println("Total = "+b.total );
            }

        }
    }

    class ThreadB extends Thread
    {
        int total;
        public void run()
        {
            synchronized(this)
            {
                System.out.println("Current thread : "+Thread.currentThread().getName());
                for(int i=0;i<100;i++)
                {
                    total = total + i;
                }
                notify();
            }
        }
    }

      

+3


source to share


3 answers


synchronized(this)

means that you will not be able to enter that block of code if another thread is inside a block of code that is also synchronized with the referenced object this

.

synchronized(b)

means that you will not be able to enter that block of code if another thread is inside a block of code that is also synchronized with the referenced object b

.



Thus, they do the same. The only difference is the object that is used to lock.

Note that waiting, synchronizing and notifying an object of type Thread is really a very bad idea. This confuses things and will lead to unwanted behavior because other methods (like join ()) also use Thread as a monitor.

+5


source


Think of it as a child's play, of who is holding [any object] to speak. Whoever holds the monitor object gets executed in computational terms.

The monitor is the object you are blocking on, at any given time only one thread is accessing the code protected by the sync block for each monitor object. The object itself is arbitrary and doesn't have much weight for synchronization (although you need to watch out for reassigning variables as well as null

references). Also, JB Nizet brings up a good point here when synchronizing on an object Thread

, since many internal VM methods do this, you can call the bazaar, catch errors and deadlocks.

The two threads entering different sync blocking blocks on different monitors will execute at the same time , similar to two separate groups of people playing / taking part in the Who Ever Holds xxx to Speak game. Locking on this

is just a convenient way to demonstrate uniform lock synchronization without creating additional lock objects.

In your case ThreadB b

, this is the same object pointed to this

from the class ThreadB

, which means that only one thread can enter any of your defined sync blocks at once. The order is highly dependent on which thread ran first, the thread scheduler, and even the underlying system.

The main reason for monitor objects is that complex thread protection mechanisms can be implemented. Imagine a system in which each sync block is the only thread access (i.e. at any moment any thread enters the sync block will hold every other thread in the entire VM trying to enter the sync block), this will not only lead to massive slowing down performance just doesn't make sense. Why do two unrelated application modules block on each other if they don't share data and never interact?



Of course, the solution is for one module to use one (or more) monitored objects that are not / are not linked to another module, so both can run simultaneously independently of each other (assuming this is the desired behavior).

To clarify, you can write:

class MultiThreadingTest{
    public static void main(String[] args){
        ThreadB b = new ThreadB();
        b.setName("Thread B");
        b.start();

        synchronized(b.lock){
            System.out.println("Current thread : "+ Thread.currentThread().getName());   

            try{
                System.out.println("Waiting for b to complete...");
                b.lock.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }

            System.out.println("Total = " + b.total );
        }

    }
}

class ThreadB extends Thread{
    public final Object lock = new Object();

    int total;

    public void run(){
        synchronized(lock){
            System.out.println("Current thread : "+Thread.currentThread().getName());
            for(int i = 0; i < 100; i++){
                total = total + i;
            }

            lock.notify();
        }
    }
}

      

to exactly the same effect as the code you were using (even better, since it resolves conflict with Thread.join () and other methods).

+4


source


In my understanding, no. The 'this' object in the run () method and the 'b' object in the main () method are the same.

Therefore, the "main" thread cannot acquire the lock until the thread has finished executing.

Also notify () in the run () method seems redundant in this case as its at the end of the method and the lock on the monitor will be rejected in some way.

PS: Look around for similar questions that may have already been asked on the forum. They can help provide additional insight.

0


source







All Articles