Назовите к ожиданию Объекта Java () синхронизацию потока повреждений

public class Main2 {
    public static void main(String[] args) {
        new Test2().start();
        new Test2().start();
    }
}

class Test2 extends Thread {
    @Override
    synchronized public void run() {
        try {
            System.out.println("begin wait");
            wait();
        } catch (Exception ex) {
        }
    }
}

Как фактический результат запущения теста: начните ожидают, начинаются, ожидают, два раза от двух потоков. Контраст по отношению к ожидаемому результату: начните ожидают, только один раз от одного из двух потоков, потому что ожидают () называют в синхронизируемом выполнении () методом. Почему мог назвать к ожиданию Объекта () синхронизацию потока повреждения?

Thans много!


    public class Main3 {

    public static void main(String[] args) {
        Test3 t = new Test3();
        new Thread(t).start();
        new Thread(t).start();
    }
}

class Test3 implements Runnable {
    synchronized public void run() {
        try {
            System.out.println("begin wait");
            wait();
        } catch (Exception ex) {
        }
    }
}

@akf и @Sean Owen

Спасибо за Ваши ответы. Извините за мою ошибку теперь я изменил код для размещения синхронизации в выполнение того же объекта (), результат остался: начните ожидают, начинаются, ожидают, два раза.

@akf

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

Вы могли уточнить немного?

5
задан Bill the Lizard 30 August 2011 в 03:24
поделиться

4 ответа

  1. Объект, который вы синхронизируете в этом примере, не класс, а экземпляр, поэтому каждый новый объект Test2 будет синхронизироваться на другом мониторе.
  2. Метод, который вы, возможно, ищете здесь, это sleep, а не wait. wait освободит блокировку, которую захватил synchronized, и будет снова захвачена, как только поток получит уведомление.

Обратите внимание, что для корректной работы вашего теста вам понадобится блокировка на общем объекте. Если вы хотите увидеть wait в действии, я создал простое приложение, в котором будет всплывать фрейм с кнопкой "Notify". Будут запущены два потока, которые ждут общий объект и, в свою очередь, получают уведомление при нажатии кнопки.

public static void main(String[] args)
{
    final Object lock = new Object(); 

    final JFrame frame = new JFrame("Notify Test");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JButton button = new JButton("Notify");
    button.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent evt) {
            synchronized(lock) {
                lock.notify();
            }
        }
    });
    frame.add(button);

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            frame.setVisible( true );
        }
    });

    new Thread(new Runnable() {
        public void run() {
            synchronized(lock) {
                try {
                    System.out.println("1. starting");
                    lock.wait();
                    System.out.println("1. step 1");
                    lock.wait();
                    System.out.println("1. step 2");
                } catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
            }
        }
    }).start();
    new Thread(new Runnable() {
        public void run() {
            synchronized(lock) {
                try {
                    System.out.println("2. starting");
                    lock.wait();
                    System.out.println("2. step 1");
                    lock.wait();
                    System.out.println("2. step 2");
                } catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
            }
        }
    }).start();

}

Для простого объяснения wait, JavaDoc всегда является хорошим местом для начала:

Заставляет текущий поток ждать, пока другой поток не вызовет метод notify() или метод notifyAll() для этого объекта. Другими словами, этот метод ведет себя точно так же, как если бы он просто выполнял вызов wait(0).

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

10
ответ дан 18 December 2019 в 16:35
поделиться

У вас есть два разных объекта Test2. Синхронизированные методы блокируют объект. Они не получают одну и ту же блокировку, поэтому не следует печатать дважды.

2
ответ дан 18 December 2019 в 16:35
поделиться

простой пример, который может вам помочь:

        public class test {
            public static void main(String[] args) {
                Prova a=new Prova();
                new Test2(a).start();
                new Test2(a).start();
            }
        }
        class Prova{
            private boolean condition;

            public void f(){

                while(condition){
                    //Thread.currentThread  Returns a reference to the currently executing thread object.
                    //Thread.getName() return name Thread
                    System.out.println(Thread.currentThread().getName()+" begin wait");
                    try{
                        wait();
                    }catch(InterruptedException c){return;}
                }       

                System.out.println(Thread.currentThread().getName()+" first to take the mutex");
                condition=true;

            }
        }
        class Test2 extends Thread {
            private Prova a;
            private static boolean condition;


            public Test2(Prova a){
                this.a=a;
            }
            @Override

             public void run() {
               synchronized(a){
                try {           
                    a.f();           
                } catch (Exception ex) {
                }
               }
            }
        }

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

1
ответ дан 18 December 2019 в 16:35
поделиться

резюме к механизму wait/notify:

1)текущий поток достигает синхронизированного блока кода одного объекта, который содержит вызов wait(), он конкурирует с другими потоками за блокировку (монитор объекта), как победитель он выполняет блок, пока не встретит вызов wait().

2)вызывая wait(), текущий поток освобождает блокировку для других конкурирующих потоков, затем останавливает выполнение, ожидая уведомления от другого потока, которому удалось получить блокировку.

JavaDoc:

Поток становится владельцем монитора объекта одним из трех способов:

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

- Путем выполнения тела синхронизированного оператора который синхронизируется на объекте.

- Для объектов типа Class, путем выполнения синхронизированного статического метода этого класса.

3)другой поток достигает очередного синхронизированного блока кода того же объекта, который содержит вызов notify/notifyAll(), он конкурирует с другими потоками за блокировку, как победитель он выполняет блок до завершения вызова notify/notifyAll(). Он освободит блокировку либо вызовом wait(), либо в конце выполнения блока.

4)при получении notify/notifyAll(), текущий поток конкурирует за блокировку, как победитель продолжает выполнение с того места, где остановился.

простой пример:

    public class Main3 {

    public static void main(String[] args) {
        Test3 t = new Test3();
        new Thread(t).start();
        new Thread(t).start();
        try {
            Thread.sleep(1000);
        } catch (Exception ex) {
        }
        t.testNotifyAll();
    }
}

class Test3 implements Runnable {

    synchronized public void run() {

        System.out.println(Thread.currentThread().getName() + ": " + "wait block got the lock");
        try {
            wait();
        } catch (Exception ex) {
        }
        System.out.println(Thread.currentThread().getName() + ": " + "wait block got the lock again");
        try {
            Thread.sleep(1000);
        } catch (Exception ex) {
        }
        System.out.println(Thread.currentThread().getName() + ": " + "bye wait block");

    }

    synchronized void testNotifyAll() {
        System.out.println(Thread.currentThread().getName() + ": " + "notify block got the lock");
        notifyAll();
        System.out.println(Thread.currentThread().getName() + ": " + "notify sent");
        try {
            Thread.sleep(2000);
        } catch (Exception ex) {
        }
        System.out.println(Thread.currentThread().getName() + ": " + "bye notify block");
    }
}

вывод:

Thread-0(или 1): wait block got the блокировку

Thread-1(или 0): блок ожидания получил блокировку

main: notify block got the блокировка

main: уведомление отправлено

main: пока блок уведомления

Thread-0(или 1): блок ожидания снова получил блокировку

Thread-0(или 1): пока блок ожидания

Thread-1(или 0): блок ожидания снова получил блокировку

Thread-1(или 0): пока wait block

-1
ответ дан 18 December 2019 в 16:35
поделиться