【问题标题】:Tracing Guarded Blocks in Java在 Java 中跟踪受保护的块
【发布时间】:2017-12-10 18:25:54
【问题描述】:

我已经为这个简单的并发 Oracle 问题苦苦挣扎了几天,它模拟了生产者/消费者。这是我第一次使用受保护的块、等待和 notifyAll。但是,我知道这些方法的作用;我不知道先发生什么步骤。我将尽我所能在下面追踪问题,你们可以告诉我我是否正确。

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

删除类

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();
    }
}

【问题讨论】:

    标签: java concurrency


    【解决方案1】:

    我没有完整的答案,但我确实有几点看法。

    如果它们循环,则包装等待的 while 将导致异常。 wait 需要锁,但 wait 会释放锁。幸运的是,您不应该遇到这种行为。

    您可能会遇到实例变量未跨线程更新的问题。您同步,然后等待。这为这些变量提供了具有不同值的机会。将它们标记为 volatile 会有所帮助。

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

    【讨论】:

    • 我只是在跟踪第一条消息的步骤,该步骤将在其他消息中重复。我喜欢你所说的等待如何要求和释放锁。
    猜你喜欢
    • 2013-12-18
    • 2012-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-02
    • 1970-01-01
    相关资源
    最近更新 更多