synchronized(this)和类的几个synchronized方法之间的区别是什么?

4
在《编程面试揭秘》(Wrox出版社)一书中,生产者消费者问题的代码在名为IntBuffer的类中,对于每个produce()和consume()方法都使用了'synchronized'关键字。这与在这些方法中使用'synchronized(this)'有什么不同吗?该书指出,“当一个线程在produce()中忙于等待时,没有线程可以进入consume(),因为这些方法是同步的。”我觉得这不符合书中代码的逻辑,因为当一个线程在produce()中忙于等待时,其他线程可以进入consume(),这破坏了互斥的概念。所以,应该将produce和consume方法都完全同步才对。
public class IntBuffer
{
    private int index;
    private int[] buffer = new int[8];

    // Function called by producer thread
    public synchronized void produce(int num) {
        while(index == buffer.length - 1) {
            try { wait();}
            catch(InterruptedException ex) {}
        }
        buffer[index++] = num;
        notifyAll();
    }

    // Function called by consumer thread
    public synchronized int consume() {
        while(index == 0) {
            try { wait();}
            catch(InterruptedException ex) {}
        }
        int ret = buffer[--index];
        notifyAll();
        return ret;
    }
}

3
将一个方法标记为synchronized会像synchronized(this)块一样在this对象上进行同步。它不会在方法或其他任何地方进行同步。 - user2357112
通常情况下,生产者和消费者都需要在同一个对象上进行同步。不过,如果要确定的话,我们可能需要查看确切的代码。 - markspace
一个 synchronized 方法在其执行之前会获取一个监视器。对于实例方法,将使用与 this(调用该方法的对象)关联的监视器。 - Radiodef
4个回答

6

3
欢迎来到Stack Overflow!我建议你删除你的回答中的最后一行,以使其更符合网站风格。(如果每个人在修复错别字时都添加了一个“编辑”行,实际上几乎每个答案都会有这些行。) - Ellen Spertus

1
使用synchronized(this)需要调用线程与使用synchronized修饰方法的实例方法调用相同的锁。生成的字节码存在一些差异,但这是一个非常低级别的区别。
synchronized关键字的目的是保护共享状态免受并发访问。生产和消费方法使用相同的内部状态,因此它们都受到相同锁的保护。
发布的代码看起来很好,我唯一的小问题是我会让方法抛出InterruptedException而不是捕获它。生产和消费方法都需要调用线程获取正在调用该方法的实例上的锁。

0

问:这与在每个方法内部使用synchronized(this)有什么不同吗? 答:没有区别,通过使用块(synchronize(this)),您可以同步代码的一部分,而不是整个方法。 例如:

public void m1(){
// some code
synchronized(this){ 
// thread-safe code 
}

我想同时同步两种方法,而不是单独地同步。使用 synchronize(this) 是否能满足我的目的?因为'this'是当前实例,所以它应该锁定整个实例,即在任何时候只有一个方法(produce()和consume()中的一个)会被线程处理。 - AnujaP
1
synchronize(this) 的作用与同步实例方法完全相同,这就是您现在拥有的。 您发布的代码是正确的,请在进行更改之前尝试理解它。请参见EJP的答案。 - markspace
是的,没错。您需要在不同的对象上进行同步,或者您可以使用其他并发原语来从生产者向供应者发送信号,反之亦然。 - fg78nc

0
这与在每个方法内部使用synchronized(this)有什么不同吗?
没有。
书上说,“当一个线程在produce()中忙于等待时,没有线程可以进入consume(),因为方法是同步的。”我觉得这对书中的代码来说并不合理,因为当一个线程在produce()中忙于等待时,没有线程可以进入produce()。然而,其他线程可以进入consume(),这破坏了互斥的想法。
那不正确。两个方法都在同一个对象上同步,因此只能有一个线程在任一方法中,除非调用了wait(),而它确实被调用了,这会释放锁。 produce和consume方法应该完全同步,对吗?
是的,你说它们是。不清楚你在这里问什么。

我同意"不清楚"的部分,OP发布的代码似乎是正确的。我只想强调一下wait()会释放锁。这允许生产者内部的代码停止并使消费者内部的代码重新启动,我认为这可能是OP误导自己的地方。 - markspace

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接