单线程间通信 多线程间通信

朱雀 2024-03-16 11:51 161阅读 0赞

单线程间通信


















首先实现一个EventQueue,该Queue有如下三种状态:
·队列满——最多可容纳多少个Event,好比一个系统最多同时能够受理多少业务一样;
·队列空——当所有的Event都被处理并且没有新的Event被提交的时候,此时队列将是空的状态;
·有Event但是没有满——有新的Event被提交,但是此时没有到达队列的上限。
  1. public class EventQueue {
  2. private final int max;
  3. static class Event {
  4. }
  5. private final LinkedList<Event> eventQueue = new LinkedList<>();
  6. private final static int DEFAULT_MAX_EVENT = 10;
  7. public EventQueue() {
  8. this(DEFAULT_MAX_EVENT);
  9. }
  10. public EventQueue(int max) {
  11. this.max = max;
  12. }
  13. public void offer(Event event) {
  14. synchronized (eventQueue) {
  15. if (eventQueue.size() >= max) {
  16. try {
  17. console(" the queue is full.");
  18. eventQueue.wait();
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. console(" the new event is submitted");
  24. eventQueue.addLast(event);
  25. eventQueue.notify();
  26. }
  27. }
  28. public Event take() {
  29. synchronized (eventQueue) {
  30. if (eventQueue.isEmpty()) {
  31. try {
  32. console(" the queue is empty.");
  33. eventQueue.wait();
  34. } catch (InterruptedException e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. Event event = eventQueue.removeFirst();
  39. this.eventQueue.notify();
  40. console(" the event " + event + " is handled.");
  41. return event;
  42. }
  43. }
  44. private void console(String message) {
  45. System.out.printf("%s:%s\n", currentThread().getName(), message);
  46. }
  47. }






上述代码中,在EventQueue中定义了一个队列,offer方法会提交一个Event至队尾,如果此时队列已经满了,那么提交的线程将会被阻塞,这是调用了wait方法的结果。同样take方法会从队头获取数据,如果队列中没有可用数据,那么工作线程就会被阻塞,这也是调用wait方法的直接结果。此外,还可以看到一个notify方法,该方法的作用是唤醒那些曾经执行monitor的wait方法而进入阻塞的线程。
  1. public class EventClient {
  2. public static void main(String[] args) {
  3. final EventQueue eventQueue = new EventQueue();
  4. new Thread(() -> {
  5. for (; ; ) {
  6. eventQueue.offer(new EventQueue.Event());
  7. }
  8. }, "Producer").start();
  9. new Thread(() -> {
  10. for (; ; ) {
  11. eventQueue.take();
  12. try {
  13. TimeUnit.MILLISECONDS.sleep(10);
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. }, "Consumer").start();
  19. }
  20. }






Producer线程模拟提交Event的客户端几乎没有任何的延迟,而Consumer线程则用于模拟处理请求的工作线程(上面的EventQueue目前只支持一个线程的Producer和一个线程的Consumer,也就是单线程间的通信)。
  1. Producer the new event is submitted
  2. Producer the new event is submitted
  3. Producer the new event is submitted
  4. Producer the new event is submitted
  5. Producer the new event is submitted
  6. Producer the new event is submitted
  7. Producer the new event is submitted
  8. Producer the new event is submitted
  9. Producer the new event is submitted
  10. Producer the new event is submitted
  11. Producer the queue is full.
  12. Consumer the event thread.pcpattern.single.EventQueue$Event@4e879704 is handled.
  13. Producer the new event is submitted
  14. Producer the queue is full.
  15. Consumer the event thread.pcpattern.single.EventQueue$Event@66e5ec31 is handled.
  16. Producer the new event is submitted
  17. Producer the queue is full.
  18. Consumer the event thread.pcpattern.single.EventQueue$Event@64056de6 is handled.
  19. Producer the new event is submitted
  20. Producer the queue is full.
  21. Consumer the event thread.pcpattern.single.EventQueue$Event@84a769f is handled.
  22. Producer the new event is submitted
  23. Producer the queue is full.
  24. Consumer the event thread.pcpattern.single.EventQueue$Event@7a87ef25 is handled.
  25. Producer the new event is submitted
  26. Producer the queue is full.
  27. Consumer the event thread.pcpattern.single.EventQueue$Event@334a0020 is handled.
  28. Producer the new event is submitted
  29. Producer the queue is full.
  30. Consumer the event thread.pcpattern.single.EventQueue$Event@7cef31f2 is handled.
  31. Producer the new event is submitted
  32. Producer the queue is full.
  33. Consumer the event thread.pcpattern.single.EventQueue$Event@27ca5e7e is handled.
  34. Producer the new event is submitted
  35. Producer the queue is full.
  36. ...






通过上述的输出日志可以看出,Producer线程很快就提交了10个Event数据,此时队列已经满了,那么它将会执行eventQueue的wait方法进而进入阻塞状态,Consumer线程由于要处理数据,所以会花费大概10毫秒的时间来处理其中的一条数据,然后通知Producer线程可以继续提交数据了,如此循环往复。






讲解了两个线程间的通信,只有一个线程对EventQueue进行offer操作,也只有一个线程对EventQueue进行take操作,如果多个线程同时进行take或者offer,那么上面的程序就会出现问题。

多线程间通信

生产者消费者







只需要将如上代码的临界值的判断if更改为while,将notify更改为notifyAll即可
  1. public class EventQueuePC {
  2. private final int max;
  3. static class Event {
  4. }
  5. private final LinkedList<Event> eventQueue = new LinkedList<>();
  6. private final static int DEFAULT_MAX_EVENT = 10;
  7. public EventQueuePC() {
  8. this(DEFAULT_MAX_EVENT);
  9. }
  10. public EventQueuePC(int max) {
  11. this.max = max;
  12. }
  13. private void console(String message) {
  14. System.out.printf("%s:%s\n", currentThread().getName(), message);
  15. }
  16. public void offerSafe(Event event) {
  17. synchronized (eventQueue) {
  18. while (eventQueue.size() >= max) {
  19. try {
  20. console(" the queue is full.");
  21. eventQueue.wait();
  22. } catch (InterruptedException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. console(" the new event is submitted");
  27. eventQueue.addLast(event);
  28. eventQueue.notifyAll();
  29. }
  30. }
  31. public Event takeSafe() {
  32. synchronized (eventQueue) {
  33. while (eventQueue.isEmpty()) {
  34. try {
  35. console(" the queue is empty.");
  36. eventQueue.wait();
  37. } catch (InterruptedException e) {
  38. e.printStackTrace();
  39. }
  40. }
  41. Event event = eventQueue.removeFirst();
  42. this.eventQueue.notifyAll();
  43. console(" the event " + event + " is handled.");
  44. return event;
  45. }
  46. }
  47. }

-——————————————————————————————————————读书笔记摘自书名:Java高并发编程详解:多线程与架构设计 作者:汪文君

发表评论

表情:
评论列表 (有 0 条评论,161人围观)

还没有评论,来说两句吧...

相关阅读

    相关 线通信

    为什么需要线程通讯 线程是操作系统调度的最小单位,有自己的栈空间,可以按照既定的代码逐步的执行,但是如果每个线程间都孤立的运行,那就会造资源浪费。所以在现实中,我们需要这

    相关 ios 线通信

    一、什么是多线程 一个iOS程序就像一个圆,不断循环,直到将它切断。一个运行着的程序就是一个进程或者叫做一个任务,一个进程至少包含一个线程,线程就是程序的执行流。iOS中

    相关 线通信

    线程和线程之间不是独立的个体,它们彼此之间可以互相通信和协作。 线程通信就是在线程之间传递信息,保证他们能够协同工作。在线程间进行通信后,系统之间的交互性会更强大,在大大提高

    相关 线通信

    一、引言 线程与线程之间不是相互独立的存在,它们彼此之间需要相互通信和协作。最典型的例子就是生产者-消费者问题。下面首先介绍 wait/notify 机制,并对实现该机制

    相关 线通信

    注意: 必须在同步方法中使用wait和notify方法,因为执行wait和notify的前提条件是必须持有同步方法(或块)的monitor的所有权,否则将会抛出异常