【问题标题】:Are the methods get and put only synchronized so that we can call notifyAll() in the following code方法 get 和 put 是否仅同步,以便我们可以在以下代码中调用 notifyAll()
【发布时间】:2016-03-15 21:48:05
【问题描述】:

我试图阅读 Producer Consumer 解决方案,但遇到了以下代码:

package SampleProjects;

public class ProducerConsumerTest {

    public static void main(String[] args) {
        CubbyHole c = new CubbyHole();
        Producer p1 = new Producer(c, 1);
        Consumer c1 = new Consumer(c, 1);
        p1.start();
        c1.start();
    }
}

class CubbyHole {

    private int contents;
    private boolean available = false;

    public synchronized int get() {
        while (available == false) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        available = false;
        notifyAll();
        return contents;
    }

    public synchronized void put(int value) {
        while (available == true) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        contents = value;
        available = true;
        notifyAll();
    }
}

class Consumer extends Thread {

    private final CubbyHole cubbyhole;
    private final int number;

    public Consumer(CubbyHole c, int number) {
        cubbyhole = c;
        this.number = number;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            int value = cubbyhole.get();
            System.out.println("Consumer #" + this.number + " got: " + value);
        }
    }
}

class Producer extends Thread {

    private final CubbyHole cubbyhole;
    private final int number;

    public Producer(CubbyHole c, int number) {
        cubbyhole = c;
        this.number = number;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            cubbyhole.put(i);
            System.out.println("Producer #" + this.number + " put: " + i);
            try {
                sleep((int) (Math.random() * 100));
            } catch (InterruptedException e) {
            }
        }
    }
}

在这段代码中,两个线程都调用了不同的方法,即生产者线程只关心put方法,消费者线程只关心get方法,所以我想知道当我们有一个循环来检查时为什么我们需要同步它们对于内容“while(available)”

然后我删除了 synchronized 关键字,它抛出了一个 IllegalStateMonitor 异常

所以我的问题是我们是否需要同步关键字才能调用 notifyAll()

【问题讨论】:

    标签: java multithreading synchronized


    【解决方案1】:

    因为notifyAllwait 都要求调用线程拥有调用该方法的对象上的监视器。

    投掷:

    IllegalMonitorStateException - 如果当前线程不是该对象监视器的所有者。

    由于您在this 上调用notifyAllwait,因此您需要this 对象的监视器。 synchronized 实例方法为您提供了这一点。

    【讨论】:

    • 我明白了,但是看看代码,我们是否需要在方法声明中添加同步关键字
    • @kapilchhattani 您要么需要synchronized 方法,要么需要明确使用synchronized(this)
    • 因此,如果同步了 put() 方法是否意味着其他线程也无法调用 get() 方法。我的意思是同步在方法上,所以这也限制了对象的其他方法被调用。
    • @kapil 也许你应该阅读一下synchronized
    • 那个链接解决了很多问题。谢谢。
    【解决方案2】:

    在方法上设置同步有几个效果:

    • 它允许 wait 和 notifyAll 通过让 2 个线程共享控制通知的监视器来工作。对 CubbyHole 实例调用 notifyAll 只会通知正在等待同一个 CubbyHole 实例的线程。

    • 它为 CubbyHole 对象的实例成员建立内存可见性,因此一旦线程拥有监视器,就可以保证看到这些变量的当前值。 JVM 可以积极地缓存值或重新排序指令,它依靠像 synchronized 关键字这样的标记来知道它应该对这些优化施加什么限制。

    将同步放在方法上意味着线程需要获取调用该方法的实例的监视器,然后才能开始执行该方法。因此,cubbyhole 对象的 put 和 get 方法使用相同的监视器,如果一个线程正在执行其中一个方法,则阻止另一个线程进入另一个线程。请注意,等待释放线程对锁的持有(允许其他线程工作),等待线程必须重新获取监视器才能离开等待。

    【讨论】:

    • 谢谢内森。我有点困惑 synchronized 关键字是如何工作的。您的解释和 Sotirios 的链接消除了疑虑。
    • @kapilchhattani “......它建立了内存可见性......”这是一个关键概念。在wait()notify() 之前要求您的程序持有锁是库作者敦促您同步对服务员正在等待的任何内容的所有访问(即contents 和@987654324 @ 你的例子中的变量)。几乎所有线程间通信都是通过共享变量进行的,Java 语言规范不保证如果您不使用适当的同步将如何实现。
    【解决方案3】:

    使用了 Synchronized 关键字,因此没有两个线程可以同时执行这些方法。应该只允许一个线程访问 put 和 get 方法。持有 CubbyHole 锁的线程将能够执行 get 和 put 方法。

    如果您不同步 get 和 put,将会出现错误情况。例如两个场景-

    1. 如果可用 == false 并且两个生产者线程同时访问 put 方法。假设线程 1 将 10 分配给内容,线程 2 分配 20 并且可用 == true。那么消费者线程将获得 10 还是 20 的值是多少?

    2. 如果可用 == true 并且两个使用者线程同时访问 get 方法。两者都将继续执行,因为 get 不同步,并且两者都将获得相同的值,这是错误的。

    同步put方法的目的是只有一个生产者线程可以生产,其他生产者线程要等到这个生产出来的值被一个消费者线程消费完。

    同步get方法的目的是只有一个消费者线程可以读取生产的值,而其他消费者线程等待,然后通过设置available为false来通知生产者生产。

    【讨论】:

      猜你喜欢
      • 2017-04-23
      • 2020-10-30
      • 2020-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-02
      相关资源
      最近更新 更多