生产者和消费者模式的好处是能够实现异步和解耦,即生产者生产出消息后不需要立马等到消息的执行结果而继续向下执行,在多线程技术中采用同步队列的方式来达到消息的生产者和消费者解耦的目的。
我们这个实例中实现是生产者不停的往同步队列中塞数据,而消费者从同步队列中取出数据进行处理。
Wrong类代码:
package com.zte.ems.thread; import java.util.concurrent.ConcurrentLinkedQueue; public class Wrong { private ConcurrentLinkedQueue<Integer> linkedQueues = new ConcurrentLinkedQueue<Integer>(); // 私有构造函数,防止通过new的方式创建,另外在构造函数中启动内部线程 private Wrong() { Worker work = new Worker(); new Thread(work).start(); } private static Wrong wrong = new Wrong(); // wr:使用单例创建Wrong对象,这个多个线程便可以共享一个wrong对象了。 public static Wrong getWrInstance() { if (wrong == null) { wrong = new Wrong(); return wrong; } else { return wrong; } } // 将生成出来的数据添加到队列中 public void put(Integer number) { linkedQueues.add(number); System.out.println("加入到同步队列的数据为:" + number); } // 另一个线程不停得从队列中取出数据 public void get() { while (!linkedQueues.isEmpty()) { Integer number = linkedQueues.remove(); System.out.println("从同步队列中取出的数字为:" + number); } } public class Worker implements Runnable { @Override public void run() { while (true) { get(); } } } }
ThreadMain类代码:
package com.zte.ems.thread; public class ThreadMain { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { if (i % 5 == 0) { Wrong.getWrInstance().put(i); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }).start(); } }
最终实现的结果:
由于我们只是简单的模拟,因此生产出来的消息非常简单,只是一些数字,但是在实际的项目开发中,生产的消息可以是具体的业务类。然后消费者再从Wrong类下的同步队列中进行取出处理。
另外,在单一服务器内部我们可以通过多线程共享同步队列的方式来实现异步和解耦,即处在业务逻辑前面的线程将消息数据输出写入到同步队列中,处在业务逻辑后面的线程再从同步队列中读取出消息数据进行处理。
但是在目前比较流行的分布式系统环境下, 多个服务器集群则是通过分布式消息队列的方式来实现异步和解耦,比较流行的消息中间件有ActiveMQ、kafka、RocketMQ等。分布式消息队列可以看成是内存队列的分布式部署。