两个列表之间的同步

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了两个列表之间的同步相关的知识,希望对你有一定的参考价值。

我有以下使用Java并发的问题。

[一家餐厅有3位客户和炊具。它们全部通过2个列表更改信息。一个用于下订单的列表,另一个用于下饭菜的列表。客户将订单发送到订单列表,电磁炉读取该订单。炊具将准备好的饭菜发送给饭菜清单上的客户。我将炊具和客户实现为处理这两个列表的线程。此问题的目的是同步对列表的访问。不幸的是,线程之间的wait()notifyAll()顺序不好,并且我没有得到什么问题。我的代码如下。谁能指出我的代码有问题吗?

编辑

问题是客户和炊具挂起而没有消耗所有食物,正如我们从输出中看到的。

Tony:    Client orders.
Tony:    The meal is still not ready.
Cooker:  Cooking Fish soup for Tony
Cooker:  The cooker will serve the meal Fish soup for Tony
Cooker:  Waiting for orders to cook.

Restaurant.java

import java.util.ArrayList;
import java.util.List;

public class Restaurant
{
   public static void main(String[] args)
   {
      List<Order> orderQueue = new ArrayList<>();
      List<Dish> dishesQueue = new ArrayList<>();

      // Client 1
      String clientName1 = "Tony";
      List<Order> personalOrders = new ArrayList<>();
      personalOrders.add(new Order(clientName1, "Fish soup"));
      personalOrders.add(new Order(clientName1, "Duck rice"));
      personalOrders.add(new Order(clientName1, "Coffee"));
      personalOrders.add(new Order(clientName1, "Pudding"));
      Thread tclient1 = new Thread(new Client(personalOrders, orderQueue, dishesQueue), clientName1);

      // Client 2
      String clientName2 = "John";
      personalOrders = new ArrayList<>();
      personalOrders.add(new Order(clientName2, "Stew"));
      personalOrders.add(new Order(clientName2, "Cake"));

      Thread tclient2 = new Thread(new Client(personalOrders, orderQueue, dishesQueue), clientName2);

      // Client 3
      String clientName3 = "Mike";
      personalOrders = new ArrayList<>();
      personalOrders.add(new Order(clientName3, "Hotdog"));
      personalOrders.add(new Order(clientName3, "Coffee"));
      Thread tclient3 = new Thread(new Client(personalOrders, orderQueue, dishesQueue), clientName3);

      Thread tCooker = new Thread(new Chef(orderQueue, dishesQueue), "Cooker");
      tclient1.start();
      tclient2.start();
      tclient3.start();

      tCooker.start();
   }
}

Chef.java

import java.util.List;

class Chef implements Runnable
{
   private final List<Order> orders;
   private final List<Dish> dishes;

   public Chef(List<Order> sharedOrders, List<Dish> sharedDishes)
   {
      this.orders = sharedOrders;
      this.dishes = sharedDishes;
   }

   @Override
   public void run()
   {
      while (true)
      {
         try
         {
            Order order = cook();
            serve(order);
         }
         catch (InterruptedException ex)
         {
            ex.printStackTrace();
         }
      }
   }

   private Order cook() throws InterruptedException {
      Order order = null;
      synchronized (orders) {
         if (orders.isEmpty()) {
            System.out.println(Thread.currentThread().getName() + ":\t Waiting for orders to cook.");
            Thread.sleep(1000);
            orders.wait();
         } else {
            order = orders.remove(0);
            System.out.println(Thread.currentThread().getName() + ":\t Cooking " + order.getDish() + " for " + order.getClientName());
            orders.notifyAll();
         }
      }
      return order;
   }

   private void serve(Order order) throws InterruptedException
   {
      synchronized (dishes)
      {
         if (dishes.isEmpty()) {
            System.out.println(Thread.currentThread().getName() + ":\t The cooker is waiting for more requests");
            dishes.wait();
         }

//         else {
         Thread.sleep(1000);
         Dish meal = new Dish(order.getClientName(), order.getDish());
         System.out.println(Thread.currentThread().getName() + ":\t The cooker will serve the meal " + meal.getDish() + " for " + meal.getClientName());
         dishes.add(meal);
         dishes.notifyAll();
//         }
      }
   }
}

Client.java


import java.util.Collections;
import java.util.List;

class Client implements Runnable
{
   private final List<Order> orders;
   private final List<Order> personalOrders;
   private final List<Dish> dishes;

   public Client(List<Order> personalOrders, List<Order> orders, List<Dish> dishes)
   {
      this.personalOrders = personalOrders;
      this.orders = orders;
      this.dishes = dishes;
   }

   @Override
   public void run()
   {
      while (!personalOrders.isEmpty())
      {
         try
         {
            request(getPersonalOrders().remove(0));
            consume();
         } catch (InterruptedException ex)
         {
            ex.printStackTrace();
         }
      }
      System.out.println(Thread.currentThread().getName() + ":\t Acabou de comer.");
   }

   private void request(Order order) throws InterruptedException {
      synchronized (orders) {
         System.out.println(Thread.currentThread().getName() + ":\t Cliente faz pedido");
         orders.add(order);
         Thread.sleep(1000);
         orders.notifyAll();
      }
   }

   private void consume() throws InterruptedException
   {
      synchronized (dishes)
      {
         if (dishes.isEmpty())
         {
            System.out.println(Thread.currentThread().getName() + ":\t The meal is still not ready.");
            dishes.wait();
         }
//         else {
         Thread.sleep(1000);
         Dish meal = dishes.remove(0);
         System.out.println(Thread.currentThread().getName() + ":\t " + meal.getClientName() + " ready to eat " + meal.getDish());
         dishes.notifyAll();
//         }
      }
   }

   public List<Order> getPersonalOrders() {
      return personalOrders;
   }
}


答案

此声明:

this.dishes = Collections.synchronizedList(dishes);

使this.dishesdishes不同。在其中一个对象上进行同步和通知不会影响另一个对象。

这就是为什么您的客户永远不会收到有关准备好的菜肴的通知。

以上是关于两个列表之间的同步的主要内容,如果未能解决你的问题,请参考以下文章

Android:处理同步网络调用

如何在导航抽屉中的两个片段之间传递数据

这两个代码片段之间有区别吗?如果有,那又如何? [复制]

片段之间的共享数据(父列表视图和子列表视图)

带有两个列表片段的可滚动布局

13 个非常有用的 Python 代码片段