Java 生产者-消费;消费者如何停止?
所以我模拟了我的生产者消费者问题,我有下面的代码。我的问题是:如果消费者处于常数状态,那么他如何停止(true) 在下面的代码中,我添加了Java 生产者-消费;消费者如何停止?,java,producer-consumer,Java,Producer Consumer,所以我模拟了我的生产者消费者问题,我有下面的代码。我的问题是:如果消费者处于常数状态,那么他如何停止(true) 在下面的代码中,我添加了 if (queue.peek()==null) Thread.currentThread().interrupt(); 这在本例中非常有效。但在我的现实设计中,这不起作用(有时生产者“放置”数据需要更长的时间,因此在使用者中引发的异常是不正确的。一般来说,我知道我可以
if (queue.peek()==null)
Thread.currentThread().interrupt();
这在本例中非常有效。但在我的现实设计中,这不起作用(有时生产者“放置”数据需要更长的时间,因此在使用者中引发的异常是不正确的。一般来说,我知道我可以放置“有毒”数据,例如对象是XYZ,我可以在使用者中检查它。但这种有毒会使代码看起来很糟糕。不知道是否有人有不同的方法
public class ConsumerThread implements Runnable
{
private BlockingQueue<Integer> queue;
private String name;
private boolean isFirstTimeConsuming = true;
public ConsumerThread(String name, BlockingQueue<Integer> queue)
{
this.queue=queue;
this.name=name;
}
@Override
public void run()
{
try
{
while (true)
{
if (isFirstTimeConsuming)
{
System.out.println(name+" is initilizing...");
Thread.sleep(4000);
isFirstTimeConsuming=false;
}
try{
if (queue.peek()==null)
Thread.currentThread().interrupt();
Integer data = queue.take();
System.out.println(name+" consumed ------->"+data);
Thread.sleep(70);
}catch(InterruptedException ie)
{
System.out.println("InterruptedException!!!!");
break;
}
}
System.out.println("Comsumer " + this.name + " finished its job; terminating.");
}catch (InterruptedException e)
{
e.printStackTrace();
}
}
公共类ConsumerThread实现可运行
{
私有阻塞队列;
私有字符串名称;
私有布尔值IsFirstTime=true;
公共使用者读取(字符串名称,阻塞队列)
{
this.queue=队列;
this.name=name;
}
@凌驾
公开募捐
{
尝试
{
while(true)
{
如果(IsFirstTime)
{
System.out.println(name+“正在初始化…”);
睡眠(4000);
IsFirstTime=false;
}
试一试{
if(queue.peek()==null)
Thread.currentThread().interrupt();
整数数据=queue.take();
System.out.println(name+“consumered-->”+数据);
睡眠(70);
}捕获(中断异常ie)
{
System.out.println(“InterruptedException!!!!”);
打破
}
}
System.out.println(“Comsumer”+this.name+“完成了它的工作;正在终止”);
}捕捉(中断异常e)
{
e、 printStackTrace();
}
}
}不要在线程上使用中断,而是在不再需要时中断循环:
if (queue.peek()==null)
break;
或者,您也可以使用变量标记关闭操作挂起,然后断开循环并在以下情况后关闭循环:
if (queue.peek()==null)
closing = true;
//Do further operations ...
if(closing)
break;
在现实世界中,大多数消息都带有某种类型的头,用于定义消息类型/子类型或可能不同的对象 您可以创建一个命令和控制对象或消息类型,告诉线程在收到消息时执行某些操作(如关闭、重新加载表、添加新侦听器等)
通过这种方式,您可以让一个命令和控制线程将消息发送到正常的消息流中。您可以让CNC线程与大型系统中的操作终端对话,等等。如果您的队列可以在您希望消费者终止之前清空,那么您需要一个标志来告诉线程何时停止。添加一个setter方法,以便生产者可以告诉消费者关闭。然后修改代码,以代替:
if (queue.isEmpty())
break;
检查代码
if (!run)
{
break;
}
else if (queue.isEmpty())
{
Thread.sleep(200);
continue;
}
A:无法保证仅仅因为
peek
返回null
,生产商就停止了生产。如果生产商只是放慢了速度怎么办?现在,消费者退出,生产商继续生产。因此,“peek”->“break”的想法基本上失败了
B:如果出现以下情况,则从使用者设置“完成/运行”标志并在生产者中读取也会失败:
字符串:
final String EOF = new String();
// Producer
while ((line = br.readLine()) != null)
queue.put(line);
br.close();
// signal end of input
queue.put(EOF);
// Consumer
while (true)
{
try
{
String line = queue.take();
// Reference equality
if (line == EOF)
break;
System.out.println(line);
linesWrote++;
}
catch (InterruptedException ie)
{
}
}
您可以将此类型安全模式用于毒药:
public sealed interface BaseMessage {
final class ValidMessage<T> implements BaseMessage {
@Nonnull
private final T value;
public ValidMessage(@Nonnull T value) {
this.value = value;
}
@Nonnull
public T getValue() {
return value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ValidMessage<?> that = (ValidMessage<?>) o;
return value.equals(that.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
@Override
public String toString() {
return "ValidMessage{value=%s}".formatted(value);
}
}
final class PoisonedMessage implements BaseMessage {
public static final PoisonedMessage INSTANCE = new PoisonedMessage();
private PoisonedMessage() {
}
@Override
public String toString() {
return "PoisonedMessage{}";
}
}
}
public class Producer implements Callable<Void> {
@Nonnull
private final BlockingQueue<BaseMessage> messages;
Producer(@Nonnull BlockingQueue<BaseMessage> messages) {
this.messages = messages;
}
@Override
public Void call() throws Exception {
messages.put(new BaseMessage.ValidMessage<>(1));
messages.put(new BaseMessage.ValidMessage<>(2));
messages.put(new BaseMessage.ValidMessage<>(3));
messages.put(BaseMessage.PoisonedMessage.INSTANCE);
return null;
}
}
public class Consumer implements Callable<Void> {
@Nonnull
private final BlockingQueue<BaseMessage> messages;
private final int maxPoisons;
public Consumer(@Nonnull BlockingQueue<BaseMessage> messages, int maxPoisons) {
this.messages = messages;
this.maxPoisons = maxPoisons;
}
@Override
public Void call() throws Exception {
int poisonsReceived = 0;
while (poisonsReceived < maxPoisons && !Thread.currentThread().isInterrupted()) {
BaseMessage message = messages.take();
if (message instanceof BaseMessage.ValidMessage<?> vm) {
Integer value = (Integer) vm.getValue();
System.out.println(value);
} else if (message instanceof BaseMessage.PoisonedMessage) {
++poisonsReceived;
} else {
throw new IllegalArgumentException("Invalid BaseMessage type: " + message);
}
}
return null;
}
}
公共密封接口基本消息{
最后一个类ValidMessage实现BaseMessage{
@非空
私人最终T值;
公共有效消息(@Nonnull T值){
这个值=值;
}
@非空
公共T getValue(){
返回值;
}
@凌驾
公共布尔等于(对象o){
如果(this==o)返回true;
如果(o==null | | getClass()!=o.getClass())返回false;
ValidMessage that=(ValidMessage)o;
返回值.equals(即.value);
}
@凌驾
公共int hashCode(){
返回Objects.hash(值);
}
@凌驾
公共字符串toString(){
返回“ValidMessage{value=%s}”。格式化(值);
}
}
最后一个类TownedMessage实现BaseMessage{
public static final-毒物消息实例=new-毒物消息();
私人中毒信息(){
}
@凌驾
公共字符串toString(){
返回“中毒消息{}”;
}
}
}
公共类生产者实现了可调用{
@非空
私有最终阻塞队列消息;
生产者(@Nonnull BlockingQueue消息){
this.messages=消息;
}
@凌驾
public Void call()引发异常{
messages.put(新的BaseMessage.ValidMessage(1));
messages.put(新的BaseMessage.ValidMessage(2));
messages.put(新的BaseMessage.ValidMessage(3));
messages.put(BaseMessage.毒物消息.INSTANCE);
返回null;
}
}
公共类使用者实现了可调用{
@非空
专用最终封锁队列