2

虽然我确实了解线程间通信的要点以及在监视器上使用等待和通知以确保同步 Put/Get 操作 - 我试图理解为什么我们需要下面代码中的Thread.sleep()当我们有一个有效的等待/通知机制时,生产者和消费者?如果我删除了 thread.sleep() - 输出会下地狱!

import java.io.*;
import java.util.*;

public class Test {
    public static void main(String argv[]) throws Throwable {

        Holder h = new Holder();
        Thread p = new Thread(new Producer(h), "Producer");
        Thread c = new Thread(new Consumer(h), "Consumer");
        p.start();
        c.start();
    }
}

class Holder {
    int a;
    volatile boolean hasPut;

    public synchronized void put(int i) {
        while (hasPut) {
            try {
                System.out.println("The thread " + Thread.currentThread().getName() + " Going ta sleep..."); 
                wait(1000);
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
        this.a = i;
        hasPut = true;
        notifyAll();
    }

    public synchronized int get() {
        while (!hasPut) {
            try {
                System.out.println("The thread " + Thread.currentThread().getName() + " Going ta sleep..."); 
                wait(1000);
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
        hasPut = false;
        notifyAll();
        return this.a;
    }
}

class Producer implements Runnable {
    Holder h;
    public Producer(Holder h) {
        this.h = h;
    }

    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("Putting : "+i); 
            h.put(i);
            try {
                Thread.sleep(10);
            } catch (InterruptedException ie) {
            }
        }
    }
}

class Consumer implements Runnable {
    Holder h;
    public Consumer(Holder h) {
        this.h = h;
    }

    public void run() {
        for (int i = 0; i < 1000; i++) {
            int k = h.get();
            System.out.println("Getting : "+k); 
            try {
                Thread.sleep(10);
            } catch (InterruptedException ie) {
            }
        }
    }
}
4

2 回答 2

1

我认为您对控制台输出感到困惑。

重要的是.get(),消费者中的每个人是否都从生产者那里获得了所有元素。当您删除所有令人困惑的System.out.行并使用

class Consumer implements Runnable {
    Holder h;
    public Consumer(Holder h) {
        this.h = h;
    }

    public void run() {
        for (int i = 0; i < 1000; i++) {
            int k = h.get();
            if (k != i)
                System.out.println("Got wrong value " + k + "expected value " + i); 
        }
    }
}

您将看到您的代码运行良好。

我认为您的困惑来自看起来像这样的输出

Getting : 990
Putting : 993
Getting : 991
Getting : 992
The thread Consumer Going ta sleep...
Getting : 993

但你也看到所有的gets 都在正确的顺序,所有的puts 也是。因此,当涉及多个线程时,这是输出在 Java 中的工作方式的问题。

于 2013-09-19T17:41:17.790 回答
0

一个线程将读取数据,并且迭代可能需要超过获取数据的次数。由于所有线程同时访问数据并处理数据的次数超过了预期的次数,因此应该有 Thread.sleep 特定毫秒。

我遇到了同样的问题,在增加 thread.sleep() 后它读取一次并处理一次

于 2014-05-28T12:21:00.393 回答