Pergunta

I just want to get a deeper understanding of the inherent mechanisms while synchronizing. I prepared 3 examples. And I have questions that refer to each of them. So here is the first example:


public class SyncExamples 
{

    SyncClass sync1, sync2;


    public void execute1()
    {
        sync1 = new SyncClass();
        sync1.process();
    }


    public void execute2()
    {
        sync2 = new SyncClass();
        sync2.process();
    }



    class SyncClass
    {

        public synchronized void process()
        {

        }
    }
}

The method process() of SyncClass is synchronized. But due to the fact that in the class SyncExamples two different objects of SyncClass are created they both can be executed concurrently, can't they. They refer to different objects so there isn't any synchronization. Is it right?

The second example:


public class SyncExamples 
{

    SyncClass sync1 = new SyncClass();


    public void execute1()
    {       
        sync1.process();
    }


    public void execute2()
    {       
        sync1.process();
    }




    class SyncClass
    {

        public synchronized void process()
        {

        }
    }
}

So in this example they refer to the very same object. So here we have a mutex. They are synchronized. But let's come to the example most interesting for me.


public class SyncExamples 
{

    SyncClass sync1 = new SyncClass();
    ReadWriteLock lock = new ReentrantReadWriteLock(); 


    public void execute1()
    {       
        lock.writeLock().lock();
        sync1.process();
        lock.writeLock().unlock();
    }


    public void execute2()
    {       
        execute1();
    }


    public void execute3()
    {       
        sync1.process();
    }


    public void execute4()
    {       
        execute1();
    }


    class SyncClass
    {

        public void process()
        {

        }
    }
}

execute2() starts execute1(). execute1() locks sync1.process(). For this reason execute4() has to wait until sync1.process() is unlocked by execute1(). But what about execute3()? It does not refer to execute1() but calls directly sync1.process() without any lock. So the lock set by execute1() is not valid for execute3()? Is that right? The lock is only valid for those calls that refer to execute1() as this method defines a lock?

the following example I added one day later:


public class SyncExamples 
{

    List list = new ArrayList(); 


    public void processList1()
    {       
        synchronized(list)
        {
        }
    }


    public void processList2()
    {       
        synchronized(list)
        {
        }
    }


    public void execute3()
    {       
        processList1();
    }


    public void execute4()
    {       
        processList2();
    }
}

I would like to clarify this one last example. Now I have a list that I want to synchronize. Method processList1() synchronizes the list... method processList2() does it as well. But can they be executed concurrently? Does synchronized lock the list globally (I mean for all other accesses from other methods) or only in conjunction with the specific method? I still don't understand if execute3() and execute4() can be executed concurrently in this example as they refer to different methods. Synchronized prevents a second access to its block. But there are several methods that want to get access to the list and they use their own synchronized blocks. So if processList1() locks the list, is this list then locked for processList2()? Or is this lock not valid for processList2() as it is a different method?

Foi útil?

Solução

First question: correct
Second case: yes, acts like a mutex
Third question: correct


Answer to the edit:

A synchronized block uses its argument object as the lock (or, better, mutex) for the block. So that if two threads reach critical sections synchronized on the same object, only one thread will be allowed to enter its critical section, while the other one waits until this one exits from the critical section.

A synchronized method is just syntactic sugar for the synchronized block so that

class SyncClass
{
    public synchronized void process()
    {

    }
}

could be written as

class SyncClass
{
    public void process()
    {
        synchronized(this)
        {
            // whole body of process() inside this block
        }
    }
}

So, to answer your questions

  • synchronized will lock list (or any other object used as its argument) globally, not just for a specific method. You can synchronize on an object anywhere in the code and the synchronized sections will run with mutual exclusion irrespective of the containing methods/classes or the call hierarchy, etc.
  • processList1() and processList2() will not execute concurrently. Only one can execute at a time. (This assumes you have no code outside the synchonized blocks.)
  • execute3() and execute4() can execute concurrently but only up to the point they reach the synchronized sections. That is, calls to processList1() and processList2() and any code you have before these calls the execute3/4() methods can execute concurrently but code inside the synchronized sections cannot be executed concurrently.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top