gpt4 book ai didi

java - 如何让线程等待某个事件的发生

转载 作者:行者123 更新时间:2023-11-30 06:25:14 25 4
gpt4 key购买 nike

你能帮我一下吗?

我想做的是一个打印机示例。将会有更多的打印机和更多的文档等待打印。

打印机是一个线程,它会 hibernate 直到文档到达,然后打印它,然后再次 hibernate 。

PrinterManager 也是一个线程。它从队列中收集文档并将其发送到免费的打印机。我正在使用 Semaphore 来查找免费打印机。

问题出在等待通知对上。打印机应等待经理发送文档。然后等待 1 秒并“打印”它。作为锁定对象,我使用stick

由于某种原因,它不起作用。文档已成功发送到打印机,但打印机未唤醒。你能帮我吗,为什么?

打印机线程:

public class Printer extends Thread {

private final Semaphore semaphore;
private final Object stick;
private String document;

public Printer(Semaphore semaphore, Object stick) {
this.semaphore = semaphore;
this.stick = stick;
}

public void setDocument(String document) {
this.document = document;
}

@Override
public void run() {
while (true) {
try {
stick.wait();
Thread.sleep(1000);
System.out.println("Printing: " + document);
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

经理线程:

public class PrinterManager extends Thread {

private final Printer[] printers = new Printer[1];
private final Object stick = new Object();
private final Semaphore semaphore = new Semaphore(printers.length);
private final DocumentQueue queue;

public PrinterManager(DocumentQueue queue) {
this.queue = queue;
printers[0] = new Printer(semaphore, stick);
}

@Override
public void run() {
while (true) {
try {
semaphore.acquire();
String toPrint = takeNextDocument();
printers[0].setDocument(toPrint);
synchronized (stick) {
stick.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

private String takeNextDocument() throws InterruptedException {
return queue.take();
}
}

最佳答案

我想知道打印机运行1000次会打印多少次文档(你会做一个实验吗?)。

但首先将 stick.wait() 放入同步块(synchronized block)中打印机的 run 方法中,否则您将在其中收到 IllegalMonitorStateException 异常。

您遇到了称为竞争条件和死锁的并发问题。这意味着结果取决于代码的执行顺序。有时您可能很幸运,程序会按您的预期运行。但在其他时候,您会遇到死锁(这是另一个并发编程问题)。

假设指令按该顺序执行:

  1. PrinterManager.run() 获取信号量

  2. PrinterManager.run() 将文档设置为打印机

  3. PrinterManager.run() 在棒上执行通知

  4. Printer.run() 执行 stick.wait()

...这就是陷入僵局的原因。PrinterManagerPrinter 开始等待stick 之前通知了stick。然后,PrinterManager 获取信号量中的最后一个许可,并开始等待,直到 Printer 释放一些许可(它永远不会,它会等待!)。两个对象开始互相等待,但都被阻塞了。

但是 Printer 可能会在 PrinterManager 通知棒上的对象之前开始等待,而不是按预期工作。这就是为什么你会出现竞争条件,你永远无法预测会发生什么,这是非常糟糕的。

作为一个简单的解决方案(不是最好的,但快速且无需您可能不熟悉的其他技术的帮助),您可以摆脱坚持。改为引入两个计数器:

numberOfFinishedPrintTasks(使Printer在每轮后递增)

lastSubscribedPrintTaskNumber(每次提交后,让 PrinterManager 将其设置为 numberOfFinishedPrintTasks + 1)。

PrinterManager必须检查条件numberOfFinishedPrintTasks == lastSubscribedPrintTaskNumber这意味着打印机完成了所有工作并且可以提交新任务。

附注不要继承 Thread 类。您无需向 Thread 添加任何新功能,只需让它运行特定作业即可。为此,您应该创建一个实现 Runnable 接口(interface)的对象并将该对象传递给新的 Thread 实例。

关于java - 如何让线程等待某个事件的发生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47308915/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com