Многопоточный небольшой тест, хороший анализ wait, notify, notifyAll в потоках

Java

В java связью между потоками можно управлять с помощью wait, notify, notifyAll. Как видно из названий, эти три метода относятся к многопоточности, но что может вас удивить, так это то, что эти три метода являются не методами класса Thread или интерфейса Runnable, а тремя локальными методами класса Object. .

在这里插入图片描述

Кроме того, я собрал сборник вопросов для интервью за 20 лет, включая сводку по spring, concurrency, database, Redis, Distributed, dubbo, JVM, микросервисам и т. д. При необходимости вы можете получить его сами:Документация Тенсент

На самом деле понять это несложно.При вызове wait и notify/notifyAll Объекта необходимо убедиться, что вызывающий код синхронизирован с Объектом, то есть он должен быть эквивалентен synchronized(obj){ .... ..} может вызывать методы wait и notify/notifyAll объекта obj, иначе будет сообщено об ошибке:

  java.lang.IllegalMonitorStateException:current thread not owner

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

Когда несколько потоков содержат один и тот же объект, если они хотят войти внутрь синхронизированного (объекта) {...}, они должны получить блокировку объекта. Синхронизированный механизм гарантирует, что не более чем 1 поток может получить объект. замок объекта, как показано ниже:

在这里插入图片描述

Давайте посмотрим на роль этих трех методов:

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

Основное различие между notify и notifyAll заключается в том, что notify пробуждает только поток, ожидающий блокировки текущего объекта, а notifyAll пробуждает все. Стоит отметить, что: notify — локальный метод, и какой поток будить, контролирует виртуальная машина; не все потоки могут выполняться сразу после notifyAll, они просто выпрыгивают из состояния ожидания, а потом будут конкурировать за объектные замки.

Ниже приведен пример общего производителя и потребителя. Класс объекта сообщения:

package com.podongfeng;

/**
 * Title: Message.class<br>
 * Description: 消息实体<br>
 * Create DateTime: 2016年04月17日 下午1:27 <br>
 *
 * @author podongfeng
 */
public class Message {
}

Режиссер:

package com.podongfeng;

import java.util.ArrayList;
import java.util.List;

/**
 * Title: Producer.class<br>
 * Description: 消息生产者<br>
 * Create DateTime: 2016年04月17日 下午1:28 <br>
 *
 * @author podongfeng
 */
public class Producer extends Thread {

    List<Message> msgList = new ArrayList<>();

    @Override public void run() {
        try {
            while (true) {
                Thread.sleep(3000);
                Message msg = new Message();
                synchronized(msgList) {
                    msgList.add(msg);
                    msgList.notify(); //这里只能是notify而不能是notifyAll,否则remove(0)会报java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Message waitMsg() {
        synchronized(msgList) {
            if(msgList.size() == 0) {
                try {
                    msgList.wait();
                } catch(InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return msgList.remove(0);
        }
    }
}

потребитель:

package com.podongfeng;

/**
 * Title: Consumer.class<br>
 * Description: 消息消费者<br>
 * Create DateTime: 2016年04月17日 下午1:28 <br>
 *
 * @author podongfeng
 */
public class Consumer extends Thread {

    private Producer producer;

    public Consumer(String name, Producer producer) {
        super(name);
        this.producer = producer;
    }

    @Override public void run() {
        while (true) {
            Message msg = producer.waitMsg();
            System.out.println("Consumer " + getName() + " get a msg");
        }
    }

    public static void main(String[] args) {
        Producer p = new Producer();
        p.start();
        new Consumer("Consumer1", p).start();
        new Consumer("Consumer2", p).start();
        new Consumer("Consumer3", p).start();
    }
}

Потребительский поток вызывает waitMsg для получения объекта сообщения. Если список msgList пуст, поток переходит в состояние ожидания, производственный поток создает объект msg physique каждые 3 секунды и помещает его в список msgList. После завершения вызовите notify для пробуждения. потребительский поток для потребления.

Наконец, напомнить снова:wait, notify, notifyAll Класс Thread не является интерфейсом или методом Runnable, а является методом трех собственных классов Object. При вызове этих трех методов текущий поток должен получить блокировку этого объекта.

Последняя практика: маленький лайк, удачи, следите, оставайтесь в молодости, дайте небольшое вознаграждение, и зарплата взлетит до небес. . .

在这里插入图片描述