Java 生产者-消费者问题 生产者是有限的,消费者也是有限的。 问题在于何时停止,而不是如何运行 通信可以通过任何类型的阻塞队列进行。 不能依赖于对队列下毒(PriorityBlockingQueue) 无法依赖于锁定队列(SynchronousQueue) 不能完全依赖报价/投票(SynchronousQueue) 可能还有更奇特的队列存在
在另一个(可能是惰性的)序列上创建排队序列。排队的人 seq将在背景中生成一个具体的seq,并且可以达到 n消费者面前的商品。n或q可以是整数n缓冲区 大小,或java.util.concurrent BlockingQueue的实例。笔记 如果读卡器超前于序列,则序列的读取可能会被阻塞 制片人 我迄今为止的尝试+一些测试: 欢迎使用Java或Clojure解决方案。Java 生产者-消费者问题 生产者是有限的,消费者也是有限的。 问题在于何时停止,而不是如何运行 通信可以通过任何类型的阻塞队列进行。 不能依赖于对队列下毒(PriorityBlockingQueue) 无法依赖于锁定队列(SynchronousQueue) 不能完全依赖报价/投票(SynchronousQueue) 可能还有更奇特的队列存在,java,concurrency,clojure,Java,Concurrency,Clojure,在另一个(可能是惰性的)序列上创建排队序列。排队的人 seq将在背景中生成一个具体的seq,并且可以达到 n消费者面前的商品。n或q可以是整数n缓冲区 大小,或java.util.concurrent BlockingQueue的实例。笔记 如果读卡器超前于序列,则序列的读取可能会被阻塞 制片人 我迄今为止的尝试+一些测试: 欢迎使用Java或Clojure解决方案。类读取器{ class Reader { private final ExecutorService ex = Exe
类读取器{
class Reader {
private final ExecutorService ex = Executors.newSingleThreadExecutor();
private final List<Object> completed = new ArrayList<Object>();
private final BlockingQueue<Object> doneQueue = new LinkedBlockingQueue<Object>();
private int pending = 0;
public synchronized Object take() {
removeDone();
queue();
Object rVal;
if(completed.isEmpty()) {
try {
rVal = doneQueue.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
pending--;
} else {
rVal = completed.remove(0);
}
queue();
return rVal;
}
private void removeDone() {
Object current = doneQueue.poll();
while(current != null) {
completed.add(current);
pending--;
current = doneQueue.poll();
}
}
private void queue() {
while(pending < 10) {
pending++;
ex.submit(new Runnable() {
@Override
public void run() {
doneQueue.add(compute());
}
private Object compute() {
//do actual computation here
return new Object();
}
});
}
}
}
private final ExecutorService ex=Executors.newSingleThreadExecutor();
私有最终列表已完成=新建ArrayList();
private final BlockingQueue doneQueue=new LinkedBlockingQueue();
私有int挂起=0;
公共同步对象take(){
去除酮();
队列();
对象rVal;
if(completed.isEmpty()){
试一试{
rVal=doneQueue.take();
}捕捉(中断异常e){
抛出新的运行时异常(e);
}
待定--;
}否则{
rVal=已完成。删除(0);
}
队列();
返回rVal;
}
私有无效删除一个(){
当前对象=doneQueue.poll();
while(当前!=null){
已完成。添加(当前);
待定--;
current=doneQueue.poll();
}
}
私有无效队列(){
同时(待定<10){
挂起++;
ex.submit(新的可运行(){
@凌驾
公开募捐{
add(compute());
}
私有对象计算(){
//在这里进行实际计算
返回新对象();
}
});
}
}
}
类读取器{
private final ExecutorService ex=Executors.newSingleThreadExecutor();
私有最终列表已完成=新建ArrayList();
private final BlockingQueue doneQueue=new LinkedBlockingQueue();
私有int挂起=0;
公共同步对象take(){
去除酮();
队列();
对象rVal;
if(completed.isEmpty()){
试一试{
rVal=doneQueue.take();
}捕捉(中断异常e){
抛出新的运行时异常(e);
}
待定--;
}否则{
rVal=已完成。删除(0);
}
队列();
返回rVal;
}
私有无效删除一个(){
当前对象=doneQueue.poll();
while(当前!=null){
已完成。添加(当前);
待定--;
current=doneQueue.poll();
}
}
私有无效队列(){
同时(待定<10){
挂起++;
ex.submit(新的可运行(){
@凌驾
公开募捐{
add(compute());
}
私有对象计算(){
//在这里进行实际计算
返回新对象();
}
});
}
}
}
恐怕这不是一个确切的答案,但有几句话和更多的问题。我的第一个答案是:使用clojure.core/seque
。制作人需要以某种方式传达seq的结尾,以便消费者知道何时停止,我假设生产的元素的数量事先不知道。为什么不能使用EOS标记(如果这就是队列中毒的意思)
如果我正确理解了您的可选序列
实现,当元素从您的函数外的队列中取出时,它将中断,因为通道
和q
在这种情况下会失步:通道将容纳比q
中的元素更多的(.take q)
元素,使其阻塞。可能有一些方法可以确保channel
和q
始终同步,但这可能需要实现您自己的Queue
类,它增加了太多的复杂性,我怀疑它是否值得
此外,您的实现没有区分正常EOS和由于线程中断而导致的异常队列终止,这取决于您使用它的目的,您可能想知道哪个是哪个。就个人而言,我不喜欢以这种方式使用异常-在异常情况下使用异常,而不是在正常的流控制中使用异常。恐怕这不是一个确切的答案,但有几句话和更多的问题。我的第一个答案是:使用
clojure.core/seque
。制作人需要以某种方式传达seq的结尾,以便消费者知道何时停止,我假设生产的元素的数量事先不知道。为什么不能使用EOS标记(如果这就是队列中毒的意思)
如果我正确理解了您的可选序列
实现,当元素从您的函数外的队列中取出时,它将中断,因为通道
和q
在这种情况下会失步:通道将容纳比q
中的元素更多的(.take q)
元素,使其阻塞。可能有一些方法可以确保channel
和q
始终同步,但这可能需要实现您自己的Queue
类,它增加了太多的复杂性,我怀疑它是否值得
此外,您的实现不区分正常EOS和