跟踪Java中的受保护块

时间:2017-07-06 16:13:00

标签: java concurrency

我一直在努力解决这个简单的并发Oracle问题,它为生产者/消费者建模。这是我第一次使用防护块,等待和notifyAll。但是,我知道这些方法的用途;我不先发生什么步骤。我将在下面尽可能地追踪问题,你们可以告诉我,如果我是对的。

  1. Producer / Consumer线程从主线程启动。每个都被赋予相同的Drop实例。
  2. 如果Consumer Thread比Producer快,它会获取drop上的内在锁,并尝试在循环中打印来自drop.take()的消息。但是,生产者没有向消费者提供消息,因为empty是真的。这导致线程被挂起并且锁被释放。现在正在等待。
  3. Producer Thread在循环中调用drop.put()。它获取drop上的内在锁定并继续该方法,因为empty为真,它需要为Consumer准备消息。它将empty设置为false并存储消息。调用notifyAll()来唤醒消费者线程。生产者也在等待,因为empty现在为假并且锁被释放。
  4. 由于drop.take()已被通知且生产者具有内在锁定,因此它会唤醒该方法。 Empty设置为true,并在循环中返回并打印消息。它现在通知生产者线程唤醒,因为它需要一条新消息。
  5. 制片人一直在等待。由于empty为真并且已通知线程(并且已访问锁),因此它现在可以唤醒并生成另一条消息。
  6. Drop Class

    package Store;
    
    public class Drop {
        // Message sent from producer
        // to consumer.
        private String message;
        // True if consumer should wait
        // for producer to send message,
        // false if producer should wait for
        // consumer to retrieve message.
        private boolean empty = true;
    
        public synchronized String take() {
            // Wait until message is
            // available.
            while (empty) {
                try {
                    wait();
                } catch (InterruptedException e) {}
            }
            // Toggle status.
            empty = true;
            // Notify producer that
            // status has changed.
            notifyAll();
            return message;
        }
    
        public synchronized void put(String message) {
            // Wait until message has
            // been retrieved.
            while (!empty) {
                try { 
                    wait();
                } catch (InterruptedException e) {}
            }
            // Toggle status.
            empty = false;
            // Store message.
            this.message = message;
            // Notify consumer that status
            // has changed.
            notifyAll();
        }
    }

    消费者类:

    package Store;
    
    import java.util.Random;
    
    
    public class Consumer implements Runnable {
        private Drop drop;
    
        public Consumer(Drop drop) {
            this.drop = drop;
        }
    
        public void run() {
            Random random = new Random();
            for (String message = drop.take();
                 ! message.equals("DONE");
                 message = drop.take()) {
                System.out.format("MESSAGE RECEIVED: %s%n", message);
                try {
                    Thread.sleep(random.nextInt(5000));
                } catch (InterruptedException e) {}
            }
        }
    }

    制片人类:

    package Store;
    
    
    import java.util.Random;
    
    public class Producer implements Runnable {
        private Drop drop;
    
        public Producer(Drop drop) {
            this.drop = drop;
        }
    
        public void run() {
            String importantInfo[] = {
                "Mares eat oats",
                "Does eat oats",
                "Little lambs eat ivy",
                "A kid will eat ivy too"
            };
            Random random = new Random();
    
            for (int i = 0;
                 i < importantInfo.length;
                 i++) {
                drop.put(importantInfo[i]);
                try {
                    Thread.sleep(random.nextInt(5000));
                } catch (InterruptedException e) {}
            }
            drop.put("DONE");
        }
    }

    主线程:

    public class ProducerConsumerExample {
        public static void main(String[] args) {
            Drop drop = new Drop();
            (new Thread(new Producer(drop))).start();
            (new Thread(new Consumer(drop))).start();
        }
    }

1 个答案:

答案 0 :(得分:0)

我没有完整的答案,但我确实有一些观察。

while while包含等待将导致异常,如果它们循环。等待需要锁定,但等待释放锁定。幸运的是,你不应该经历这种行为。

您可能会遇到不跨线程更新实例变量的问题。你同步,然后等待。这为这些变量提供了不同价值的机会。将它们标记为不稳定将有助于此。

你没有说出你的代码实际上做了什么......