Параллелизм потоков - синхронизация и блокировки. - PullRequest
0 голосов
/ 26 декабря 2011
import java.util.*;
import java.io.*;
import java.util.regex.*;

class ZiggyTest2 extends Thread{

    String sa;

    public ZiggyTest2(String sa){
        this.sa = sa;
    }

    public void run(){
        synchronized(sa){
            while(!sa.equals("Done")){
                try{
                    sa.wait();
                }catch(InterruptedException is){System.out.println("IE Exception");}
            }
        }

        System.out.println(sa);
    }
}

class Test{
    private static String sa = new String("Not Done");

    public static void main(String[] args){
        Thread t1 = new ZiggyTest2(sa);
        t1.start();

        synchronized(sa){
            sa = new String("Done");
            sa.notify();
        }
    }
}

Когда я запускаю вышеуказанную программу, я получаю следующее исключение:

Exception in thread "main" java.lang.IllegalMonitorStateException
        at java.lang.Object.notify(Native Method)
        at Test.main(ZiggyTest2.java:35)

Пара вопросов:

  • Почему исключение IllegalMonitorStateException?Поскольку Test.sa назначен новому объекту String, я ожидал, что поток ZiggyTest2 будет ждать неопределенно долго, потому что sa.notify () будет вызываться с блокировкой, отличной от той, которая используется в ZiggyTest2.

  • В приведенном выше примере wait () и notify () вызываются для объекта sa.В чем разница, например, при вызове notify () самостоятельно и вызове notify () / wait () с использованием объекта, например, sa.wait () и sa.notify ()?

  • Имеет ли значение, что в классе Test синхронизированный блок имеет блокировку для объекта sa, а объект sa является статическим, но в классе ZiggyTest2 синхронизированный блок использует ту же ссылку на объект sa, но с использованием нестатической ссылки?Учитывая, что один является статическим, а другой нет, будут ли они по-прежнему использовать одну и ту же блокировку?

1 Ответ

2 голосов
/ 26 декабря 2011

Когда вы выполняете

sa = new String("Done");

, вы не изменяете содержимое ссылок String на sa.Вы присваиваете новый экземпляр String (новый объект) sa.Строки неизменны.Невозможно изменить их значение.

Это означает, что вы синхронизируете по sa (первый объект: «Not Done»), затем назначаете новый объект для sa (второй объект: «Done») и вызываете notifyэто второй объект.Поскольку вы синхронизировались не со вторым объектом, а с первым, вы получаете исключение IllegalMonitorException.Вызов notify для объекта разрешен только в том случае, если вы владеете встроенной блокировкой объекта.Вот почему блокировка всегда должна быть окончательной.

Вызов notify () эквивалентен вызову this.notify ().Так что this.notify() и sa.notify() просто вызывают notify() для двух разных объектов.Первый уведомит поток, ожидающий на this, а второй уведомит поток, ожидающий на sa.

Тот факт, что переменная является статической или нет, не имеет значения.Блокировка связана с объектом, а не с его ссылкой.

...