今天是端午节,祝大家端午节快乐。今年的疫情让很多人放弃了出行的计划,宅在家里,我也是无聊,想到写点什么东西和大家分享下,希望有感兴趣的看看,如果有什么想法欢迎交流。
生产者和消费者是软件世界里很寻常的场景,然而大多数程序员平时写代码不会用到,因为很多系统都是用来查询数据展示数据,写写CRUD就好了。随着MQ的横空出世,让大家都醉心于这种好用的中间件,配置一个Topic,发送消息就调用客户端的发送接口,接收消息继承一个接口,写一个Listener,整个从生产到消费全流程就这种友好的解决了,性能和完整性更不用你担心,因为这些主流MQ都号称是几十万的TPS,4个9的可靠性。
凡事需知其然及其所以然,MQ就是一个基于生产者和消费者的最佳实践。今天想基于阻塞队列来实现生产者和消费者的场景,阻塞队列用的是ArrayBlockingQueue,一个生产者线程,一个消费者线程。
生产者代码
public class Producer implements Runnable {
BlockingQueue<Integer> queue;
public Producer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
public void run() {
while (true) {
Integer num = Double.valueOf(Math.random()*100).intValue();
this.queue.offer(num);
System.out.println("加入元素到队列:"+num);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
消费者代码
public class Consumer implements Runnable {
BlockingQueue<Integer> queue;
String name;
public Consumer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
public Consumer(String name, BlockingQueue<Integer> queue) {
this.name = name;
this.queue = queue;
}
public void run() {
while (true){
System.out.println("开始队列长度**********:"+queue.size());
Integer num = this.queue.poll();
System.out.println(name + "消费元素:**********" + num);
System.out.println("结束队列长度:"+queue.size());
try {
Thread.sleep(120);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
下面创建了一个生产者和二个消费者,因为生产者生产得快,大家可以先用一个消费者看看结果,会发现消费队列总会有元素,主要源于生产者生产的速度比消费者快,当增加一个消费者后,就会发现队列为空,被消费完了,线程等待的状况。
public class ConsumerTest {
public static void main(String[] args) {
BlockingQueue<Integer> myQueue = new ArrayBlockingQueue<Integer>(1000);
Thread producer = new Thread(new Producer(myQueue));
Thread consumer = new Thread(new Consumer(myQueue));
Thread consumer2 = new Thread(new Consumer("consumer2", myQueue));
consumer.start();
producer.start();
consumer2.start();
try {
producer.join();
consumer.join();
consumer2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
如果队列满了,对于ArrayBlockingQueue 的 offer操作来说,会直接丢弃掉插入的元素。如果想验证,可以将队列容量修改为4,然后在生产者中加入下面的代码,就会打出插入失败的元素,并且往后看,会发现这个元素不会被消费到。
public void run() {
while (true) {
Integer num = Double.valueOf(Math.random()*100).intValue();
String isSuccess = this.queue.offer(num) ? "成功":"失败";
System.out.println("加入元素到队列:"+ num +" " + isSuccess );
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
今天和大家聊了下生产者和消费者,相信大家已经大致明白了整个的过程,为大家模拟了单生产者多消费者的例子,大家也可以自己去扩展多生产者和多消费者。说到这里,还是想抛砖引玉,这个队列例子和MQ队列相比有哪些不足,MQ有哪些黑科技为大型分布式系统保驾护航。