方法是否只进行同步,以便我们可以在以下代码中调用notifyAll()

时间:2015-01-08 16:42:01

标签: java multithreading synchronized

我正在尝试阅读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方法,而Consumer线程只关注get方法,所以我想知道为什么当我们在里面有一个循环检查时我们需要同步它们内容&#34; while(可用)&#34;

然后我删除了synchronized关键字并抛出了IllegalStateMonitor Exception

所以我的问题是我们是否只需要同步关键字,以便我们可以调用notifyAll()

3 个答案:

答案 0 :(得分:1)

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

  

抛出:

     

IllegalMonitorStateException - 如果当前主题不是此对象监视器的所有者。

由于您在notifyAll上调用了waitthis,因此您需要this对象的监视器。 synchronized实例方法可以为您提供。

答案 1 :(得分:1)

对方法进行同步有几个影响:

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

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

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

答案 2 :(得分:1)

使用Synchronized关键字,这样任何两个线程都不能同时执行这些方法。只允许一个线程访问put和get方法。持有CubbyHole锁的线程将能够执行get和put方法。

如果您没有同步get和put,则会出现错误情况。例如两种情况 -

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

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

  3. 同步put方法的目的是只有一个生产者线程可以产生,而其他生产者线程应该等到一个消费者线程消耗这个产生的值。

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