2个线程可以同时访问对象的2个同步方法吗?

时间:2016-02-25 12:47:52

标签: java multithreading

这个问题在接受我的采访时被问到了。在我告诉他之前,

  

一旦线程进入实例上的任何同步方法,就没有其他方法   线程可以在同一个实例上输入任何其他同步方法。

考虑一下代码段:

Q1:

public class Q1 {
    int n;
    boolean valueSet = false;

    synchronized int get() {
        while (!valueSet)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        System.out.println("Got: " + n);
        valueSet = false;
        notify();
        return n;
    }

    synchronized void put(int n) {
        while (valueSet)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        this.n = n;
        valueSet = true;
        System.out.println("Put: " + n);
        notify();
    }
}

Producer1:

public class Producer1 implements Runnable {

    Q1 q;

    Producer1(Q1 q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }

    @Override
    public void run() {

        int i = 0;
        while (true) {
            q.put(i++);
        }

    }
}

Consumer1

public class Consumer1 implements Runnable {

    Q1 q;

    Consumer1(Q1 q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }

    @Override
    public void run() {
        while (true) {
            q.get();
        }

    }

}

PC1:

public class PC1 {

    public static void main(String args[]) {

        Q1 q = new Q1();
        new Producer1(q);
        new Consumer1(q);
        System.out.println("Press Control-C to stop.");

    }
}

所以,一旦你创建了这个线程new Producer1(q),他就会问你,然后根据你的说法,synchronized int get()方法必须被同一个线程锁定,即new Producer1(q)当它访问synchronized int put()时。我说是的。

但我检查了eclipse,get可以new Consumer1(q)调用。该计划非常完美。

我哪里错了?

O / P:

enter image description here

6 个答案:

答案 0 :(得分:6)

wait()的调用将释放监视器等待的时间。

Object.wait():

的记录内容
  

当前线程必须拥有此对象的监视器。 线程   释放此监视器的所有权并等待另一个线程   通知在此对象的监视器上等待的线程唤醒   要么通过调用notify方法,要么通过调用   notifyAll方法。然后线程等待直到它可以   重新获得监视器的所有权并恢复执行。

答案 1 :(得分:1)

  

一旦线程进入实例上的任何同步方法,就没有其他方法   线程可以在同一个实例上输入任何其他同步方法。

您忘记在此添加的内容是"除非锁被释放"

...在您的示例中,调用wait时就是这种情况。

documentation指定:

  

线程释放此监视器的所有权并等到另一个监视器   线程通知线程等待此对象的监视器唤醒   通过调用notify方法或notifyAll方法。

由于锁定被释放,您将进入另一个方法(条件为true,因为布尔值已被修改)。一旦进入另一个方法,再次释放锁定,然后调用notify,然后唤醒终止的旧线程(重新修改boolean以在其他方法中传递条件,并通知)。这样你就可以在两种方法之间进行步骤 ad-infinitum

答案 2 :(得分:0)

wait()notify()充当线程之间的信号,控制线程执行或不执行操作。

答案 3 :(得分:0)

该程序工作正常,因为这里有2个线程(ProducerConsumer)争夺一个锁(监视器)。当Consumer获取锁定(Q1对象)时,Producer正在等待锁定。当Consumer完成他的工作时,它会释放锁定。当调用wait()方法时,Consumer也释放锁,因为wait()将线程设置为具有锁定释放的等待状态。是Producer获取锁定并完成其工作的时候了。当Producer线程notify()调用时,Consumer继续他的工作(获取锁定时)。同样适用于Producer

恢复:Q1对象是所有线程的锁。如果它获取了某人,则其他人被阻止,答案是 - 不可能同时访问get()put()方法超过2个线程。

答案 4 :(得分:0)

我认为这个问题含糊不清。 (例如,"可访问"是什么意思?)

IMO,一个好的面试问题不应该有正确的答案和错误的答案。一个好的面试问题应该是一个对话启动器,让你有机会展示你对这个主题的了解程度。

当我询问面试问题时,我喜欢能够看清问题的候选人,并深入了解基础机制。例如,

What the JLS guarantees is that no two threads can be _synchronized_
on the same instance at the same time...

然后我们可以探讨两个线程如何同时进入同一个synchronized方法的问题? (例如,在不同的实例上同步),两个线程如何同时在同一个实例的同一个同步方法中(其中一个可能在wait()调用中),...

答案 5 :(得分:-3)

线程无法访问同步的代码块,除非它已获得对保护块的对象的锁定。在您的情况下,synchronized关键字使用已声明它的对象的锁。因此,只要线程正在执行get(),就没有其他线程可以执行put()

如果你应用它,当put()设置值时,它会通知接受该值的消费者。即使从get和put方法中删除了wait()和notify()调用

,代码也应该可以工作