线程与单锁不同步

时间:2015-07-05 21:18:26

标签: java multithreading synchronization

我无法正确同步此程序,结果也应该在第二个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();
}

}

2 个答案:

答案 0 :(得分:3)

你没有加入第二个主题:

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

应该是:

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

你还使用了poll,它不会阻止:

  

检索并删除此队列的头部,如果此队列为空,则返回null。

您可能想要使用PriorityBlockingQueue

  

如果任何线程修改队列,则多个线程不应同时访问PriorityQueue实例。而是使用线程安全的PriorityBlockingQueue类。

您可以使用take方法来避免busy-wait

  

检索并删除此队列的头部,必要时等待,直到元素可用为止。

答案 1 :(得分:3)

poll的调用不一定会消耗元素。如果队列中没有元素,则只返回null。

为了确保您有效地使用元素,您可以写:

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

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