问题陈述:从无限的整数流中识别两个连续的整数,其中这些整数由多个生产者生成,但单个消费者在再次重复相同的数字时会发出警报。
我有多个Producers
和一个Consumer
。如果我将消费者提交给同一ExecutorService
,消费者就没有开始。但是如果我在单独的Thread中运行Consumer,则Consumer线程会按预期启动。
代码:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Iterator;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class FixedBlockingQueue {
final BlockingQueue<Integer> queue;
private int capacity;
public FixedBlockingQueue(int capacity){
super();
this.capacity = capacity;
queue = new ArrayBlockingQueue<Integer>(capacity);
System.out.println("Capactiy:"+this.capacity);
}
public void addElement(Integer element){
try{
queue.put(element);
}catch(Exception err){
err.printStackTrace();
}
}
public void startThreads(){
ExecutorService es = Executors.newFixedThreadPool(1);
for ( int i =0; i < 10; i++){
es.submit(new MyProducer(this));
}
//es.submit(new MyConsumer(queue));
new Thread(new MyConsumer(this)).start();
}
public BlockingQueue<Integer> getQueue(){
return queue;
}
public static void main(String args[]){
FixedBlockingQueue f = new FixedBlockingQueue(1);
f.startThreads();
}
}
class MyProducer implements Runnable{
private FixedBlockingQueue queue;
public MyProducer(FixedBlockingQueue queue){
this.queue = queue;
}
public void run(){
for ( int i=1; i< 5; i++){
queue.addElement(new Integer(i));
System.out.println("adding:"+i);
}
}
}
class MyConsumer implements Runnable{
private BlockingQueue<Integer> queue;
Integer firstNumber = 0;
private final ReentrantLock lock = new ReentrantLock();
public MyConsumer(FixedBlockingQueue fQueue){
this.queue = fQueue.getQueue();
}
/* TODO : Compare two consecutive integers in queue are same or not*/
public void run(){
Integer secondNumber = 0;
while ( true){
try{
lock.lock();
System.out.println("queue size:"+queue.size());
if ( queue.size() > 0) {
secondNumber = queue.remove();
System.out.println("Removed:"+secondNumber);
System.out.println("Numbers:Num1:Num2:"+firstNumber+":"+secondNumber);
if ( firstNumber.intValue() == secondNumber.intValue()){
System.out.println("Numbers matched:"+firstNumber);
}
firstNumber = secondNumber;
}
Thread.sleep(1000);
}catch(Exception err){
err.printStackTrace();
}finally{
lock.unlock();
}
}
}
}
输出:
Capactiy:1
adding:1
如果我从
更改代码es.submit(new MyConsumer(queue));
//new Thread(new MyConsumer(queue)).start();
到
//es.submit(new MyConsumer(queue));
new Thread(new MyConsumer(queue)).start();
消费者线程正常启动。
输出:
Capactiy:1
adding:1
queue size:1
Removed:1
Numbers:Num1:Num2:0:1
adding:2
queue size:1
Removed:2
Numbers:Num1:Num2:1:2
adding:3
queue size:1
Removed:3
Numbers:Num1:Num2:2:3
adding:4
queue size:1
Removed:4
Numbers:Num1:Num2:3:4
adding:1
queue size:1
Removed:1
Numbers:Num1:Num2:4:1
adding:2
queue size:1
Removed:2
adding:3
Numbers:Num1:Num2:1:2
queue size:1
Removed:3
Numbers:Num1:Num2:2:3
第一种方法:
我知道消费者不会使用该号码,但理想情况下不应阻止提交其他Producer
任务。
如果是这种情况,使用ExecutorService
代替简单Threads
无法100%实现?
答案 0 :(得分:2)
您创建一个具有单个线程和一个具有固定容量的BlockingQueue
的线程池。然后您向池中提交三个任务:前两个每个尝试将五个值排入队列,然后一个使值出列何时可用。
因为您的固定大小的池只有一个线程,所以您提交给它的任务将按顺序运行,而不是并行运行。您首先提交生产者任务,因此它首先运行。但是一旦它将第一个数字排队,它就无法取得任何进一步的进展,因为队列已满。并且队列将保持永久满,因为生成器任务必须在池化线程可用于其他任务(例如消费者)之前完成。
我不确定你为什么要使用线程池,因为直接进行线程管理并不困难,特别是因为你的任务已经实现了Runnable
。但是,如果你做使用了一个池,那么确保它有足够的线程来同时容纳所有任务。
另请注意,BlockingQueue
实现应该是线程安全的,标准库提供的所有实现都是如此。因此,您无需在addElement()
中执行自己的锁定。此外,如果你确实需要执行自己的锁定,那么你不仅需要在将元素排队时,而且在将它们出列时也要这样做。
此外,如果您的生产者任务通过FixedBlockingQueue
实例间接地向底层队列添加元素,那就超出了奇怪的程度,但是让消费者任务直接进入底层队列。
并且您的FixedBlockingQueue
类的名称选择不当,因为它意味着该类实现了BlockingQueue
,但该类实际上并没有这样做。