多线程通信

x33g5p2x  于2022-03-13 转载在 其他  
字(2.2k)|赞(0)|评价(0)|浏览(316)

一 notifyAll 方法

该方法可以同时唤醒全部的阻塞线程,同样被唤醒的线程仍需要继续争取 monitor 的锁。

二 实战

1 代码

package concurrent;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;

public class EventQueue1 {
    private final int max;

    static class Event {
    }

    private final LinkedList<Event> evnetQueue = new LinkedList<>();
    private final static int DEFAULT_MAX_EVENT = 10;

    public EventQueue1() {
        this(DEFAULT_MAX_EVENT);
    }

    public EventQueue1(int max) {
        this.max = max;
    }

    public void offer(Event event) {
        synchronized (evnetQueue) {
            while (evnetQueue.size() >= max) {
                try {
                    System.out.println(" the queue is full");
                    evnetQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            System.out.println(" the new event is submitted");
            evnetQueue.addLast(event);
            evnetQueue.notifyAll();
        }
    }

    public Event take() {
        synchronized (evnetQueue) {
            while (evnetQueue.isEmpty()) {
                try {
                    System.out.println("the queue is empty");
                    evnetQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            Event event = evnetQueue.removeFirst();
            this.evnetQueue.notifyAll();
            System.out.println("the event" + event + " is handled");
            return event;
        }
    }

    public static void main(String[] args) {
        final EventQueue1 eventQueue = new EventQueue1();
        new Thread(() -> {
            for (; ; ) {
                eventQueue.offer(new EventQueue1.Event());
            }
        }, "Producer").start();

        new Thread(() -> {
            for (; ; ) {
                eventQueue.take();
                try {
                    TimeUnit.MILLISECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Consumer").start();
    }
}

2 测试

the new event is submitted
the new event is submitted
the new event is submitted
the eventconcurrent.EventQueue1$Event@6706a70b is handled
the new event is submitted
the new event is submitted
the new event is submitted
the new event is submitted
the new event is submitted
the new event is submitted
the new event is submitted
the new event is submitted
the queue is full
the eventconcurrent.EventQueue1$Event@69c1559b is handled
the new event is submitted
the queue is full
the eventconcurrent.EventQueue1$Event@6dfecc7b is handled

三 线程休息室 wait set

在虚拟机规范中存在一个 wait set 的概念,至于该 wait set 是怎样的数据结构, JDK 官方并没给出明确定义,但不管怎样,线程调用了某个对象的 wait 方法之后都会被加入该对象 monitor 关联的 wait set 中,并且释放 monitor 的所有权。

1 notify

下图是若干线程调用了 wait 方法之后被加入与 monitor 关联的 wait set 中,当另外一个线程调用该 monitor 的 notify 方法之后,其中一个线程会从 wait set 中弹出,至于是随机弹出还是先进先出的方式弹出,虚拟机规范并没有给出强制要求。

2 notifyAll

不需要考虑哪个线程会被弹出,因为 wait set 中的所有 wait 线程都会被弹出。

相关文章