这个问题在接受我的采访时被问到了。在我告诉他之前,
一旦线程进入实例上的任何同步方法,就没有其他方法 线程可以在同一个实例上输入任何其他同步方法。
考虑一下代码段:
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:
答案 0 :(得分:6)
对wait()
的调用将释放监视器等待的时间。
Object.wait():
当前线程必须拥有此对象的监视器。 线程 释放此监视器的所有权并等待另一个线程 通知在此对象的监视器上等待的线程唤醒 要么通过调用notify方法,要么通过调用 notifyAll方法。然后线程等待直到它可以 重新获得监视器的所有权并恢复执行。
答案 1 :(得分:1)
一旦线程进入实例上的任何同步方法,就没有其他方法 线程可以在同一个实例上输入任何其他同步方法。
您忘记在此添加的内容是"除非锁被释放" 。
...在您的示例中,调用wait
时就是这种情况。
线程释放此监视器的所有权并等到另一个监视器 线程通知线程等待此对象的监视器唤醒 通过调用notify方法或notifyAll方法。
由于锁定被释放,您将进入另一个方法(条件为true,因为布尔值已被修改)。一旦进入另一个方法,再次释放锁定,然后调用notify,然后唤醒终止的旧线程(重新修改boolean以在其他方法中传递条件,并通知)。这样你就可以在两种方法之间进行步骤 ad-infinitum 。
答案 2 :(得分:0)
wait()
和notify()
充当线程之间的信号,控制线程执行或不执行操作。
答案 3 :(得分:0)
该程序工作正常,因为这里有2个线程(Producer
,Consumer
)争夺一个锁(监视器)。当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()调用
,代码也应该可以工作