代码如下:
class Q {
int n;
private boolean p = false; synchronized int get() {
if (!p) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Get: " + n);
p = false;
notify();
return n;
} synchronized void put(int n) {
if (p)
try {
wait();
} catch (InterruptedException e) {
System.out.println("InterruptedException caught");
}
this.n = n;
System.out.println("Put: " + n);
p = true;
notify();
}
}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, "Consumer1").start();
new Thread(this, "Consumer2").start();
new Thread(this, "Consumer3").start();
} public void run() {
synchronized (q) {
while (true) {
q.get();
}
}
}
}class PC {
public static void main(String args[]) {
Q q = new Q();
Thread thread = Thread.currentThread();
new Producer(q);
new Consumer(q);
try {
thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Press Control-C to stop.");
}
}

解决方案 »

  1.   

    我想让生产者生一个,消费者只能有一个能拿的,但是我做的程序是消费者能拿多次;
    Put: 4625
    Get: 4625
    Get: 4625
    Get: 4625
    Put: 4626
    Get: 4626
    Get: 4626
    Get: 4626
    Put: 4627
    Get: 4627
    Get: 4627
    Get: 4627
    请问我是不是哪的锁没有锁好?
      

  2.   

    数字n可放入一个Queue内。每次放入用enqueue,拿出用dequeue。
    一个线程拿出数字后,其他线程就不会再取得同样的数字了。
      

  3.   

    我的意思是生产完了,就有人来拿,拿完了,我再生产我刚才测试了一下我的p的取值是不和我想的一样的
    Put: 778
    false
    Get: 778
    true
    Get: 778
    false
    Get: 778
    false
    p的值是false的时候生产,true时消费,现在false也消费了
      

  4.   

    if (!p) {
        try {
            wait();        // 当线程被唤醒,没有重新判断 p 的值,这里 n 的值还是之前的那一个
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }更改之后:class Q {
        int n;
        private boolean p = false;    synchronized int get() {
            while(!p) {      // 改成 while 就可以了
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("Get: " + n + " (" + Thread.currentThread().getName() + ")");
            p = false;
            notifyAll();   // 改成 notifyAll
            return n;
        }    synchronized void put(int n) {
            while(p) {       // 改成 while 就可以了
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println("InterruptedException caught");
                }
            }
            this.n = n;
            System.out.println("Put: " + n);
            p = true;
            notifyAll();  // 改成 notifyAll
        }
    }也可以使用 JDK 5 并发包中的 ReentrantLock 和 Condition 来实现:class Q {
        int n;
        private boolean p = false;
        
        private final Lock lock = new ReentrantLock();
        private final Condition canConsume = lock.newCondition();
        private final Condition canProduce = lock.newCondition();    int get() {
            lock.lock();
            try {
                while(!p) {
                    canConsume.await();
                }
                System.out.println("Get: " + n + " (" + Thread.currentThread().getName() + ")");
                p = false;
                canProduce.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            return n;
        }    void put(int n) {
            lock.lock();
            try {
                while(p) {
                    canProduce.await();
                }
                this.n = n;
                System.out.println("Put: " + n);
                p = true;
                canConsume.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }        
        }
    }
      

  5.   

    当然了,如果使用 LinkedBlockingQueue 类的话,那所有的事就不再需要亲历亲为了。如果是为了学习的话,研究一下 wait, notify 也是很不错的,呵呵 :-)
      

  6.   

    我把你的代码改了一下.请参考class Q {
    int n; private boolean p = false; synchronized int get() {
    while (!p) {
    try {
    wait();
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    System.out.println(Thread.currentThread() + "--Get: " + n);
    p = false;
    notifyAll();
    return n;
    } synchronized void put(int n) {
    while (p) {
    try {
    wait();
    } catch (InterruptedException e) {
    System.out.println("InterruptedException caught");
    }
    }
    this.n = n;
    System.out.println(Thread.currentThread() + "--Put: " + n);
    p = true;
    notifyAll();
    }
    }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, "Consumer1").start();
    new Thread(this, "Consumer2").start();
    new Thread(this, "Consumer3").start();
    } public void run() {
    synchronized (q) {
    while (true) {
    q.get();
    }
    }
    }
    }public class PC {
    public static void main(String args[]) {
    Q q = new Q();
    Thread thread = Thread.currentThread();
    new Producer(q);
    new Consumer(q);
    try {
    thread.sleep(10000);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    System.out.println("Press Control-C to stop.");
    }
    }
      

  7.   

    java多线程还没概念,来学习一下
      

  8.   

    Condition 是不是信号量?还有在我的实现方式中的
    synchronized (q) {
       while (true) {
           q.get();
       }
    }
    是不是可以不要。还有wait()方法被激活后是不是就往下执行了,不会再重新开始执行函数了吗?谢谢了线程没学好啊呵呵
      

  9.   

    还有我的get()方法中用notify()有问题吗?我只要激活我的put()方法就行了
      

  10.   

    Condition 是一个等待、唤醒的条件变量,呵呵。用 wait, notifyAll 的话,你可能也注意到了,当某个消费线程消费完了,使用 notify 或者 notifyAll 唤醒其他线程。其实我们的本意唤醒生产线程就可以了,但是 notify 或者 notifyAll 并不一定会去唤醒生产线程,被唤醒的有可能是另一个消费线程,这样的话将会导致很多的无用功,浪费系统资源。如果不用 notifyAll,而把上面的代码改成 notify 的话,那会使用生产/消费速度变得奇慢无比,就是这个原因造成的。用 Condition 的话,我们可以从可重入锁中产生两个条件变量,一个用于生产线程,一个用于消费线程。当消费线程消费完了之后,我们只要唤醒生产线程就可以了,没必要去唤醒消费线程。
      

  11.   


    不能不要!wait() 被唤醒后,会接着执行,而不是从头开始执行。
      

  12.   

    synchronized (q) {
    while (true) {
    q.get();
    }
    我加上了这句后就一直只执行第一个线程,其他的两个就不执行了
      

  13.   

    这里加同步没有什么意义,因为 q.get 方法已经同步过了。而且这个同步块中也没有什么共享变量。如果你使用的是我第一次给你的那代码的话,就不会产生问题了。我在用 ReentrantLock 测试时,是把 while(true) 这里的同步给去掉了,忘记说了,呵呵。你加上这句后一直执第一个线程,那可能是你使用了带有 ReentrantLock 和 Condition 的代码。由于使用锁不同,这个 while(true) 要加同步的话,也必须是 ReentrantLock 的那把锁。如果再使用 q 锁,由于其他地方没有在 q 锁上的 wait,导致 q 锁永远不会被释放,因此只有一个线程在运行了。如果使用可重入锁做的话,而且又有必要在 while(true) 这里加上同步的话,那么可以这样改一下:class Consumer implements Runnable {
        Q q;    Consumer(Q q) {
            this.q = q;
            new Thread(this, "Consumer1").start();
            new Thread(this, "Consumer2").start();
            new Thread(this, "Consumer3").start();
        }    public void run() {
            // 使用  Q 中的 ReentrantLock 锁
            // 把 Q 中 lock 的 private 去掉,变成包内可访问
            q.lock.lock();
            try {
                while (true) {
                    q.get();
                }
            } finally {
                // Lock 接口的锁必须在 finally 中释放掉,便于在有异常时也能正常的释放锁,以免造成死锁
                // 而用 synchronized 的话,在抛出异常时 JVM 会自动释放锁
                q.lock.unlock();  
            }
        }
    }
      

  14.   

    楼主的问题经典啊!我都不会弄呵呵j2se,多线程,socket网络,JBoss Netty研究群15161096
    欢迎加入!
      

  15.   

    我给错人了,我怎么给potahai 给了25分,我是要给你的