代码之家  ›  专栏  ›  技术社区  ›  parsecer

Java:producer-consumer两个线程停止工作,冻结

  •  1
  • parsecer  · 技术社区  · 5 年前

    我有这段代码,它从第一个数组中获取数据,并将其放入第二个数组,然后从第一个数组中删除它。它在一段时间内工作正常,但随后停止,而第一个数组中仍有要粘贴的值:

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    public class Main  {
        private static String buffer;
        private static String lock = "lock";
    
        public static void main(String[] args) throws  Exception  {
            Usb usb1 = new Usb(getListFromValues("1", "2", "3", "4", "5"));
            Usb usb2 = new Usb(getListFromValues("10", "20", "30", "40", "50"));
    
            Thread usbCutThread = new Thread(new UsbCutThread(usb1));
            Thread usbPasteThread = new Thread(new UsbPasteThread(usb2));
    
            usbCutThread.start();
            usbPasteThread.start();
    
            usbCutThread.join();
            usbPasteThread.join();
    
        }
    
        static class UsbCutThread implements Runnable  {
          private Usb usb;
          public UsbCutThread(Usb usb)  {this.usb = usb;}
    
          @Override
          public void run() {
              try {
                  System.out.println("inside cut");
                  for (int i = 0; i < usb.getData().size(); i++) {
                      buffer = usb.getValue();
                      System.out.println("cutting value " + buffer);
    
                      synchronized (lock) {
                          System.out.println("copied to buffer, waiting for paste");
                          lock.notify();
                          try {
                              lock.wait();
                          } catch (Exception e) {
                              e.printStackTrace();
                          }
                          System.out.println("erasing");
                          usb.eraseValue();
                      }
                  }
              }
            catch (Exception e)  {
                  e.printStackTrace();
            }
          }
        }
    
        static class UsbPasteThread implements Runnable  {
            private Usb usb;
            public UsbPasteThread(Usb usb)  {this.usb = usb;}
    
            @Override
            public void run() {
                try {
                    while (true) {
                        System.out.println("inside paste");
                        //while it copies, cut thread can't erase - what if copy fails
                        synchronized (lock) {
                            usb.addValue("stuff");
                            System.out.println("pasted");
                            lock.notify();
                            try {
                                lock.wait();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
    
                        }
                    }
                }
                catch (Exception e)  {
                    e.printStackTrace();
                }
            }
    
        }
    
        static class Usb  {
          List<String> data = new ArrayList<>();
    
          public Usb(List<String> data)  {this.data = data;}
    
            public String getValue()  {return data.get(data.size() - 1);}
    
            public void addValue(String value)  {
              data.add(value);
            }
    
            public void eraseValue()  {
              data.remove(data.size() - 1);
            }
    
            public List<String> getData()  {return data;}
        }
    
        public static ArrayList<String> getListFromValues(String... values)  {
            ArrayList<String> result = new ArrayList<>();
            for (String v: values)  {
                result.add(v);
            }
            return result;
        }
    }
    

    输出:

    inside cut
    inside paste
    pasted
    cutting value 5
    copied to buffer, waiting for paste
    inside paste
    pasted
    erasing
    cutting value 4
    copied to buffer, waiting for paste
    inside paste
    pasted
    erasing
    cutting value 3
    copied to buffer, waiting for paste
    inside paste
    pasted
    erasing
    
    0 回复  |  直到 5 年前
        1
  •  1
  •   akuzminykh    5 年前

    UsbCutThread 迭代自 0 usb.getData().size() :

                  for (int i = 0; i < usb.getData().size(); i++) {
    

    你在循环中 改变 大小 usb.getData() usb.eraseValue() . 显然会影响迭代的数量。在您的情况下,您将得到3次迭代,直到 i == usb.getData().size() true 然后退出循环。

    lock.wait() 当你把整件事 while (true) . 这里是你的程序不会终止的地方。

    要解决第一个问题,只需迭代到固定的限制:

                  int n = usb.getData().size();
                  for (int i = 0; i < n; i++) {
    

    我认为第二个问题其实不是你的问题,而是你想要的。所以我就到此为止。