Java 如何启动、暂停和停止生产者/消费者关系?

Java 如何启动、暂停和停止生产者/消费者关系?,java,multithreading,concurrency,Java,Multithreading,Concurrency,我肯定是在一个并发地狱。我无法找到一个好的/有效的解决方案来解决我正在尝试做的事情。我有一个生产者线程,它正在读取文本文件,并将信息放入共享的BlockedQueue中。我有一个消费者,他使用共享BlockedQueue读取数据,并对数据进行大量处理。我的GUI有三个按钮:开始、暂停和停止 生产者和消费者都实现Runnable,并提供方法来访问关于每个计算的信息(例如,返回一些统计信息或一些对象) 使用Start选项,我希望制作人打开一个文件并开始将数据放入BlockedQueue。消费者也开始

我肯定是在一个并发地狱。我无法找到一个好的/有效的解决方案来解决我正在尝试做的事情。我有一个生产者线程,它正在读取文本文件,并将信息放入共享的BlockedQueue中。我有一个消费者,他使用共享BlockedQueue读取数据,并对数据进行大量处理。我的GUI有三个按钮:开始暂停停止

生产者和消费者都实现Runnable,并提供方法来访问关于每个计算的信息(例如,返回一些统计信息或一些对象)

使用Start选项,我希望制作人打开一个文件并开始将数据放入BlockedQueue。消费者也开始获取数据并进行计算

使用Pause选项,我希望生产者停止将数据放入BlockedQueue,但同时我希望能够访问生产者的实例变量。对于消费者也是一样,我想停止做繁重的工作,但仍然能够访问消费者中定义的一些实例变量和方法

使用停止选项,我希望生产者和消费者重置。。。i、 好像从清洁开始

我的问题是如何有效地实现这一点?特别是检查暂停

像这样的psudo代码是否高效

Enum state;

class Producer implements Runnable {
    public List someList;//accessed from the event-dispatching thread 
    public void Run() {
        synchronized(state) {
            if(state == Enum.paused) {
                //do nothing
            }
            else if(state == Enum.running) {
                //put stuff into BlockedQueue
            }
            else if (state == Enum.stopped) {
               // reopen file and set state = running
            }


        }
    }
}

class Consumer implements Runnable {
    public Map someMap;//accessed from the event-dispatching thread 
    public void Run() {
        synchronized(state) {
            if(state == Enum.paused) {
                //do nothing
            }
            else if(state == Enum.running) {
                //start consuming from the BlockedQueue and do heavy computation
            }
            else if (state == Enum.stopped) {
               // clear stuff to start clean and set state = running
            }


        }
    }
}

您可以标记进入队列的消息,无论它们是数据消息还是控制消息。每个线程只有一个输入(消息)队列

我的问题是如何有效地实现这一点?特别是检查暂停?像这样的psudo代码是否高效

Enum state;

class Producer implements Runnable {
    public List someList;//accessed from the event-dispatching thread 
    public void Run() {
        synchronized(state) {
            if(state == Enum.paused) {
                //do nothing
            }
            else if(state == Enum.running) {
                //put stuff into BlockedQueue
            }
            else if (state == Enum.stopped) {
               // reopen file and set state = running
            }


        }
    }
}

class Consumer implements Runnable {
    public Map someMap;//accessed from the event-dispatching thread 
    public void Run() {
        synchronized(state) {
            if(state == Enum.paused) {
                //do nothing
            }
            else if(state == Enum.running) {
                //start consuming from the BlockedQueue and do heavy computation
            }
            else if (state == Enum.stopped) {
               // clear stuff to start clean and set state = running
            }


        }
    }
}
我认为在
消费者
生产者
上使用字段是一种很好的方法。您需要确保该字段是volatile,以便在线程之间正确同步对枚举的任何更新。或者,如果使用
synchronized
关键字,则更新时需要有
synchronized
<代码>易失性在这种情况下更好,因为没有理由阻止

 public class Consumer {
    private volatile Enum state;
    ...
    if(state == Enum.paused) {
人们提到“毒丸”是一种解决办法。当您将一个对象放入队列中时,它会改变状态。此解决方案的问题是,如果使用者正在处理对象,它将不会检查队列,因此这将不起作用。我想您可以在队列中使用
peek()
,但是
state
字段应该可以正常工作

生产者和消费者都实现Runnable,并提供方法来访问关于每个计算的信息(例如,返回一些统计信息或一些对象)

生产者
消费者
对象仍将存在并可访问。在所有情况下,您都需要确保对要在线程之间共享的字段所做的任何更新都需要正确同步

我的问题是如何有效地实现这一点?特别是检查暂停


就效率而言,
volatile
字段访问似乎比典型的字段访问慢约100倍。我不会对每一行都进行状态检查,但是如果您在每个处理循环的顶部进行检查,或者执行类似于
if(loopCounter%1000==0)
的操作来检查循环中每X次的暂停,您应该不会看到太多性能是否受到影响。

旁注:保持枚举一致。现在有一个描述状态(
isPause
),一个描述当前操作(
运行
),还有一个描述操作(
停止
)。看看
毒丸
。这个问题听起来像是Brian Goetz等人在《Java并发性实践》第7章中的营销活动。本章讨论可取消性和可中断性,并解释“……程序如何处理取消和关闭通常是区分真正健壮的并发应用程序和仅能工作的并发应用程序的因素之一。”这是一本比Joshua Bloch的《高效Java》第二版更高级的读物。,但对于那些希望用Java进行严肃并发编程的人来说,这是一本必读的书(它涵盖了毒丸)。我想说,这里的关键是掌握InterruptedException成语。@Gray,你能在这里检查我的问题吗?