线程与单锁不同步

Thread not synchronized with single lock

我无法正确同步此程序,第二个 println 中的结果也应为 0,因为这两个线程各创建和弹出 10000 次。 我必须以不同的方式同步吗?

import java.util.*;

public class Main00 {

Queue<Integer> q = new PriorityQueue<Integer>();
Random rand = new Random();

public static void main(String[] args) {
    new Main00().doStuff();
}

public void doStuff(){
    Thread t1=new Thread(new Runnable(){
        public void run(){
            for(int i=0;i<10000;i++)produce();
        }
    });
    Thread t2=new Thread(new Runnable(){
        public void run(){
            for(int i=0;i<10000;i++)consume();
        }
    });

    System.out.println("Starting threads, q size is : "+q.size());
    t1.start();
    t2.start();

    try{
        t1.join();
        t1.join();
    }catch(InterruptedException e){}

    System.out.println("Ending threads, q size is : "+q.size());
}

synchronized public void produce() {
    q.add(rand.nextInt(100));
}

synchronized public void consume() {
    q.poll();
}

}

您没有加入第二个话题:

    t1.join();
    t1.join();

应该是:

    t1.join();
    t2.join();

您还在使用 poll,它不会阻塞:

Retrieves and removes the head of this queue, or returns null if this queue is empty.

您可能想使用 PriorityBlockingQueue:

Multiple threads should not access a PriorityQueue instance concurrently if any of the threads modifies the queue. Instead, use the thread-safe PriorityBlockingQueue class.

您可以利用 take method to avoid busy-wait:

Retrieves and removes the head of this queue, waiting if necessary until an element becomes available.

poll 的调用不一定会消耗元素。如果队列中没有元素,它只是 returns null.

为了确保你有效地使用一个元素,你会写:

  while(q.poll() == null);

此外,根据 http://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html,class PriorityQueue 不是线程安全的。您应该使用线程安全的 PriorityBlockingQueue class,它有一个 poll 超时阻塞方法。