我正在阅读这个程序并且无法理解它。
class Q
{
int n;
synchronized int get()
{
System.out.println("Got: " + n);
return n;
}
synchronized void put(int n)
{
this.n = n;
System.out.println("Put: " + n);
}
}
class Producer implements Runnable
{
Q q;
Producer(Q q)
{
this.q = q;
new Thread(this, "Producer").start(); }
public void run()
{
int i = 0;
while(true)
{ q.put(i++); }
}
}
class Consumer implements Runnable
{
Q q;
Consumer(Q q)
{
this.q = q; new Thread(this, "Consumer").start();
}
public void run() { while(true) { q.get(); } }
}
class PC
{
public static void main(String args[])
{
Q q = new Q();
new Producer(q);
new Consumer(q);
System.out.println("Press Control-C to stop.");
}
}
虽然Q上的put()和get()方法是同步的,但是没有什么能阻止生产者超越消费者,也不会阻止消费者两次使用相同的队列值。因此,您将获得此处显示的错误输出:
投入:1 得到:1 得到:1 得到:1 得到:1 得到:1 投入:2 放:3 投入:4 投入:5 放:6 投入:7 得到:7
正如你所看到的,在制作人放1后,消费者开始并连续五次获得相同的内容。然后,制作人恢复并制作2到7而不让消费者有机会消费它们。我问题是为什么我们得到这样奇怪的输出,我的意思是当执行get()时它返回一个值然后线程应该从监视器退出,而不是它停留在那里并打印1次这样;然后put(),它是如何增加和打印这些值的。 ???请帮助,我知道我可能看起来很幼稚,因为我是java的新手。
答案 0 :(得分:1)
os调度程序决定执行哪个线程以及哪个线程获得锁定。它不必在线程之间交替进行针锋相对,它只是确保没有因为缺少cpu片而饿死。因此,你可以看到一个线程运行一段时间,然后另一个线程有机会。让线程有一段时间的权限可以帮助最小化上下文切换。每次调度程序切换正在运行的线程都会产生开销时,最好让线程有机会运行并完成某些操作而不是在它们之间进行抖动。
如果您希望线程在严格的交替中工作,那么您可以通过让线程等待直到Q处于有效状态来强制执行该操作:
class Q {
Integer n; // nullable
public synchronized int get() {
while (n == null) {
wait();
}
notifyAll();
System.out.println("got: " + n);
int retval = n;
n = null;
return retval;
}
public synchronized void put(int n) {
while (n != null) {
wait();
}
notifyAll();
this.n = n;
System.out.println("put: " + n);
}
}
此版本的Q将导致两个线程轮流。
如果您只希望线程放置并设置值而不交替,那么使用AtomicInteger会更简单。同步用于组合多个动作,以便它们不会受到其他线程的干扰。
答案 1 :(得分:1)
首先,您应该清楚生产者/消费者算法。 https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem
内森休斯回答肯定是你在找什么。