在本文中,我们将了解用于控制线程的wait()方法,以及notify() / notifyAll()方法。这些方法在基类java.lang.Object中定义,因此,Java 中的继承机制将这些方法提供给所有类。也就是说,当您创建自己的类及其对象时,您始终可以调用这些方法。
wait() 和 notify()/notifyAll() 方法如何工作?
- 等待()。简而言之,此方法释放监视器并将调用线程置于等待状态,直到另一个线程调用 notify () / notifyAll()方法;
- 通知()。继续之前调用过 wait() 方法的线程的工作;
- notifyAll()方法恢复之前调用过wait()方法的所有线程。
-
public final native void wait(long timeoutMillis)抛出InterruptedException;它导致当前线程等待直到它被唤醒。通常它会在被通知或中断时发生,或者直到经过一定的实时时间。
-
public final void wait()抛出InterruptedException。我们编写了一个没有参数的方法作为第二个方法并非巧合。事实上,如果你看一下它的代码,它指的是方法的第一个变体,它只有 0L 参数。
-
public final wait (long timeout, int nanos)。导致当前线程等待直到它被唤醒,通常是通过被通知或中断,或者直到一定量的实时已经过去。
Wait() 方法示例
这里我们有一个最流行的例子来说明该方法的工作原理。假设我们有一家商店、一个生产者和一个消费者。制造商将一些生产产品转移到商店,之后消费者可以取走它们。让制造商必须分别生产8种商品,消费者必须全部购买。但同时仓库中最多只能有6件物品。为了解决这个问题,我们使用wait()和notify()方法。让我们定义三个类:Market、Manufacturer和Client。run()方法中的Manufacturer使用其将 8 种产品添加到Market对象放()方法。客户端在run()方法中循环调用Market对象的get方法来获取这些商品。Market类的 put 和 get 方法是同步的。为了跟踪商品在Market类中的存在,我们检查 item 变量的值。获取产品的 get() 方法只有在至少有一个产品时才会触发。因此,在 get 方法中,我们检查产品是否丢失。如果该项目不可用,则调用wait()方法。该方法释放Market对象的监视器并阻塞 get 方法,直到notify()在同一个监视器上调用方法。当在put()方法中添加一个项目并调用notify()时, get()方法获取监视器。之后,我们的客户收到一件物品。为此,将显示一条消息,并减少该项目的值。最后,notify()方法调用向put()方法发出信号以继续。在put()方法中,类似的逻辑起作用,只是现在如果Market中的产品不超过 6 个,put()方法应该起作用。
class Market {
private int item = 0;
public synchronized void get() {
//here we use wait() method
while (item < 1) {
try {
wait();
}
catch (InterruptedException e) {
}
}
item--;
System.out.println("A client has bought 1 item...");
System.out.println("Items quantity in Market warehouse... " + item);
notify();
}
public synchronized void put() {
//here we use wait() method when the Warehouse is full
while (item >= 6) {
try {
wait();
}
catch (InterruptedException e) {
}
}
item ++;
System.out.println("Manufacturer has added 1 more item...");
System.out.println("Now there are " + item + " items in Warehouse" );
notify();
}
}
class Manufacturer implements Runnable {
Market market;
Manufacturer(Market market) {
this.market = market;
}
public void run() {
for (int i = 0; i < 8; i++) {
market.put();
}
}
}
class Client implements Runnable {
Market market;
Client(Market market) {
this.market = market;
}
public void run() {
for (int i = 0; i < 8; i++) {
market.get();
}
}
}
//wait() method test class
public class WaitTest {
public static void main(String[] args) {
Market market = new Market();
Manufacturer manufacturer = new Manufacturer(market);
Client client = new Client(market);
new Thread(manufacturer).start();
new Thread(client).start();
}
}
在这里,在get()方法中使用wait(),我们正在等待制造商添加新项目。而在添加之后,我们调用notify(),就好像说 Warehouse 上有一个地方空闲了,你可以添加更多。在put()方法中,使用wait() ,我们正在等待Warehouse上的空间释放。空间空闲后,我们添加项目,notify()启动线程,客户端可以拿起项目。这是我们程序的输出:
制造商又添加了 1 件商品...现在仓库里有 1 件商品 制造商又添加了 1 件商品...现在仓库里有 2 件商品 制造商又添加了 1 件商品...现在仓库里有 3 件商品 制造商有添加了 1 个项目... 现在仓库中有 4 个项目 制造商又添加了 1 个项目... 现在仓库中有 5 个项目 制造商又添加了 1 个项目... 现在仓库中有 6 个项目 客户已购买1 件商品... 市场仓库中的商品数量... 5 客户购买了 1 件商品... 市场仓库中的商品数量... 4 客户购买了 1 件商品... 市场仓库中的商品数量... 3客户已购买 1 件商品... 市场仓库中的商品数量... 2 客户已购买 1 件商品... 市场仓库中的商品数量... 1 客户已购买 1 件商品... 市场仓库中的商品数量...0 制造商又添加了 1 件商品... 现在仓库中有 1 件商品 制造商又添加了 1 件商品... 现在仓库中有 2 件商品 客户购买了 1 件商品... 市场仓库中的商品数量... 1 客户购买了 1 件商品...市场仓库中的商品数量...0 退出代码为 0 的流程已完成
GO TO FULL VERSION