Многопоточность Java с ожиданием и уведомлением

У меня есть этот кусок кода

public MultiThreadedSum(ArrayBuffer ArrayBufferInst)
{
    this.ArrayBufferInst = ArrayBufferInst;
    Sum = 0;
    Flag = false;
    StopFlag = false;
}

public synchronized void Sum2Elements()
{

    while(Flag)
    {
        try {wait();}
        catch (InterruptedException e){}
    }

    Flag = true;

    if (StopFlag)
    {
        notifyAll();
        return;
    }

    System.out.println("Removing and adding 2 elements.");

    Sum = ArrayBufferInst.Sum2Elements();

    notifyAll();
}

public synchronized void InsertElement()
{

    while(!Flag)
    {
        try {wait();}
        catch (InterruptedException e){}
    }

    Flag = false;

    if (StopFlag)
    {
        notifyAll();
        return;
    }

    System.out.println("Inserting the sum.");

    ArrayBufferInst.InsertElement(Sum);

    if (ArrayBufferInst.RetunrSize() == 1)
    {
        StopFlag = true;
    }

    System.out.println(ArrayBufferInst);

    notifyAll();
}

Как видите, я сначала установил для флага значение false, чтобы один из потоков мог войти в метод Sum2Elements и изменить его на true, тем самым заставив всех ждать.

Я знаю, что в синхронизированном коде только один поток может делать свое дело, ну вот у меня есть два синхронизированных метода, значит ли это, что 2 потока пытаются проводить эти методы после каждого notifyall?

И если да, то не может ли один поток войти в Sum2Elements, изменить флаг на true до того, как другой поток войдет в InsertElement, и тем самым пропустить цикл while?

Спасибо


person Assaf Malki    schedule 28.05.2013    source источник
comment
@AmitD Вы имеете в виду volatile? transient просто указывает, что поле не должно сериализоваться в классе, реализующем Serializable.   -  person FThompson    schedule 28.05.2013
comment
да. Я хотел бы исправить себя, используя volatile, как уже упоминалось   -  person Amit Deshpande    schedule 28.05.2013
comment
@OP, попробуйте использовать соглашение об именах переменных (имя должно начинаться с маленькой буквы), это сбивает с толку при чтении вашего кода.   -  person ajduke    schedule 28.05.2013


Ответы (3)


Блокировки получаются для объектов класса, а не для какого-либо конкретного синхронизированного метода. Оба метода являются методами экземпляра. Таким образом, если один из потоков ввел какой-либо синхронизированный метод для объекта, скажем, A, то любой другой поток не может ввести какой-либо синхронизированный метод для этого объекта до тех пор, пока работающий поток не вызовет метод notifyAll(). На этом этапе все ожидающие потоки конкурируют за то, чтобы стать активными, но выбор потока, который должен стать активным, зависит от планировщика потоков.

Если вы хотите, чтобы два разных потока одновременно обращались к этим синхронизированным методам, тогда два потока должны работать с двумя разными объектами класса.

person Jatin Sehgal    schedule 28.05.2013

Только один поток может удерживать блокировку объекта. И тогда только этот поток может вводить синхронизированные методы для этого объекта.

Однако поток может снять блокировку, не возвращаясь из метода, вызвав Object.wait().

Итак, ваш код выглядит хорошо!

does it mean that 2 threads are trying to conduct this methods after each notifyall? 
Ans : It is very much possible for two threads to be in two of your synchronized methods since you are calling wait().

is it not possible for one thread to enter Sum2Elements, change the flag to true before the other thread enters InsertElement, and by that skipping the while loop?
Ans : Yes this is possible again for the same reason specified above.
person Aniket Thakur    schedule 28.05.2013
comment
Что вы имеете в виду, поскольку вызываете wait()? Если бы я не использовал ожидание и имел бы только 2 синхронизированных метода с двумя потоками и снова выполнял бы их с истинным и ложным, возможно ли, чтобы два метода выполнялись вместе? а что касается второго ответа, можно ли что-нибудь сделать, чтобы этого избежать? Спасибо. - person Assaf Malki; 28.05.2013
comment
Если вы не вызовете ожидание 2, потоки не смогут выполнять два разных метода синхронизации одного и того же экземпляра класса. Причина в том, что если у кого-то есть блокировка экземпляра класса, другой поток не может получить доступ к любому другому методу синхронизации того же экземпляра, если только первый не вызывает wait(), и в этом случае thread1 снимает блокировку, но все еще остается в 1-м методе синхронизации. - person Aniket Thakur; 28.05.2013

Only one thread can execute one of two method at a time because both are synchronized though order is undefined

Как я уже сказал, один метод может выполняться одним потоком за раз только в том случае, если исполняющий поток освобождает метод lock, вызывая методwait, а другой поток получает метод lock и выполняет другой метод synchronized, что делает ваши оба утверждения возможными.

person amicngh    schedule 28.05.2013