Memory competing and sharing between threads

0

I have the following code:

class Objt
{
    public List<t> list_t1;
    public List<t> list_t2;

    public Objt() 
    {
        // faz inicializações
    }

    public void handleLists(List<t> list)
    {
        for(t e: list)
        {
           ... // manipula elementos da lista
        {
    }
}

Problem: I am free to manipulate both lists at the same time in my problem, including that is the intention. In this code, only one thread can enter that line of code for that object at a time to manipulate a list, the other would wait to manipulate another list.

Question: I could well duplicate this handleLists() method and put them with name handleList1() and handleList2() and allocate them each to a thread , but is it kind of like that, or not? Is there a more elegant solution? A Pattern ?

What I want to understand now, given the comments, is if I can use the same method handleLists() in the two threads only passing different lists to each thread and they will run in parallel.

Note: I put list_t1 and list_t2 just to illustrate a possible use.

    
asked by anonymous 02.07.2016 / 21:49

2 answers

3

In my experience it is not uncommon for you to have two independent lists requiring synchronized access to an object. It may be a sign of a violation of the Principle of Single Responsibility. But this is a matter of design and is beside the point.

Keep in mind that synchronized access to a code snippet depends on a token, that is, an object of which there is only one instance, so that whoever has it at a given time can perform the desired action, if otherwise it will have to wait for the owner of the token to release it so that it can acquire that token and take action. With the difference that the term used is not "token" but "lock" (or semaphore, monitor, etc). What I mean is that his job is to be a token. This is what synchronized access is all about: the thread that has the lock can enter the synchronized code snippet and execute it (and do operations on its lists, for example).

Any object can be a lock. When a method is synchronized , the lock is the very object that contains that method. In the case of your example, if you have such a code ...

Objt bijeto = new Objt();
bijeto.handleLists(list);

... the object bijeto will be the lock for the synchronized method handleLists() .

Choosing the most appropriate lock (s) for your case will depend on your intent. When a thread has access to list_t1 , do you want it to also have access to list_t2 ? In this case, you can use a lock only for the two lists. This lock can be the Objt object itself, or else another object that you define as the Objt attribute.

Or when a thread has access to list_t1 , do not you want it to have access to list_t2 ? In this case you will need two different locks. The lists themselves, if they are non-null and declared as final , can be used as locks for access to themselves. Or you can create two attributes lock_t1 and lock_t2 .

Note that the two code snippets below are equivalent:

Excerpt 1:

public class Objt {

    public synchronized handleList() {
        ...
    }
}

Excerpt 2:

public class Objt {

    public handleList() {
        synchronized(this) { // "this" é referência para o próprio
            ...              // objeto de classe Objt
        }
    }
}

Editing:

You have clarified that you want to have a method that receives a list as a parameter and makes changes to it. A thread will call this method by passing a list_t1 list as a parameter and another thread will call that method by passing another list_t2 list as a parameter.

If this is the only point where the lists are modified, the parallelism will work without problems and there will be no need to declare the synchronized method, as @bigown said in its response, which perfectly answers the question. It will work because the method is not making any changes in shared state, only in the state of the parameters passed to it, which in this case are independent of each other.

But avoid declaring the lists in the class that contains this same method, this only creates confusion (because if they are attributes of a class it would not be necessary to pass them as a parameter to methods of that same class).

Or stop declaring everything as public and try to learn how to use the Java access modifiers to correctly reflect your intentions in the code.

If you want to make the code more elegant, give more details about what you want to do and include more code in the question, including the threads that call that method, which shows you how it can look.

    
02.07.2016 / 22:20
4

The answer from Piovezan gives a good explanation of the problem you are having in using the method, so I will only complement it with the part that I understood differently in the question (by the way, it is not very clear at that point) / p>

If the method will simultaneously receive different lists, in the case a call in a thread will receive list_t1 and the other call in another thread will receive list_t2 and the method it will not handle the parameter list that will contain or one or the other list in each call, they will not confuse themselves, they will be called completely isolated and there will be no competition problems. So, not only is there no problem in calling this method in more than one thread at the same time, achieving parallelism, nor need to mark it as synchronized . You do not even have to sync anything internally, which may even end the parallelism depending on how it is used ( I already told you about it ).

Of course I may be wrong depending on the content of the method, which was not posted.

As an addendum, creating another method will not help at all. In fact, depending on what you do, it may even cause more problems.

    
02.07.2016 / 23:35