在多个线程上同步Java中的队列

时间:2014-06-06 15:31:07

标签: java multithreading queue

我理解同步的概念,但我现在确定为什么会以这种方式实现,所以我需要一些帮助:

我有2个帖子:

PeriodicalThread会定期收到数据(假设每5秒钟一次)并将其放入Queue(暂时使用ArrayDeque,但我不知道是否还有其他Queue {1}}实施将更好地工作)

ProccessThread会不断检查Queue以查看它是否为空。如果它不为空,它将处理数据(FIFO)

所以,首先我的实现是:

// Both threads are inner class so they have access to Queue

private Queue queue;
private boolean isReadyToProccess;


class PeriodicalThread extends Thread {
    public void run() {
        while(true) {
           if(isNewDataAvailable) {
                // create Data object
                queue.add(data);
           }
        }
    }
}

class ProcessThread extends Thread {
    public void run() {
        while(true) {
           if(!queue.isEmpty() && isReadyToProccess) {
               Data data = queue.poll();
               processData(data);
           }
        }
    }
}

private void processData(Data data) {
    // this method send data over network, and the server response callback
    // changes isReadyToProcess value to true.
}

然后当想要处理同步时,我不知道我是否应该使用lock对象(以及它是如何实现的)或者是否已经有一个包{{1实现是线程安全的(因为Queueadd()方法)

编辑:我忘记了标志poll(),表示下一个队列isReadyToProcess对象是......好了,准备好进行处理。这个标志也应该同步。

5 个答案:

答案 0 :(得分:4)

ArrayDeque不支持并发。相反,使用支持BlockingQueue等并发工作的真实队列及其java.util.concurrent包中的一个实现。我建议使用LinkedBlockingQueue

如果您需要在线程之间共享标记,最好使用AtomicBoolean而不是手动同步原始boolean字段。

注意:如果您将使用并发进程,最好使用已经支持锁定和同步开箱即用的java.util.concurrent包提供的类。

答案 1 :(得分:2)

您正在寻找Blocking Queue实施

这提供了您正在寻找的开箱即用功能。这就是为什么它最适合生产者消费者的例子。

这是一个例子

public class BlockingQueueExample {

    public static void main(String[] args) throws Exception {

        BlockingQueue queue = new ArrayBlockingQueue(1024);

        Producer producer = new Producer(queue);
        Consumer consumer = new Consumer(queue);

        new Thread(producer).start();
        new Thread(consumer).start();

        Thread.sleep(4000);
    }
}


public class Producer implements Runnable{

    protected BlockingQueue queue = null;

    public Producer(BlockingQueue queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            queue.put("1");
            Thread.sleep(1000);
            queue.put("2");
            Thread.sleep(1000);
            queue.put("3");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


public class Consumer implements Runnable{

    protected BlockingQueue queue = null;

    public Consumer(BlockingQueue queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            System.out.println(queue.take());
            System.out.println(queue.take());
            System.out.println(queue.take());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

答案 2 :(得分:1)

查看ArrayBlockingQueue和另一个BlockingQueue实现。

来自文档:

  

一个队列,它还支持在检索元素时等待队列变为非空的操作,并在存储元素时等待队列中的空间可用。

另一种选择也是ConcurrentLinkedQueue。

您可以在此处阅读有关并发队列的更多信息:

http://docs.oracle.com/javase/tutorial/collections/implementations/queue.html

答案 3 :(得分:1)

在Java 5之前,您必须实现等待/通知机制。从Java 5开始,您可以使用BlockingQueue接口的实现来解决生产者/消费者问题。

看看这个:

http://www.javamex.com/tutorials/synchronization_producer_consumer.shtml

答案 4 :(得分:0)

您可以使用java Blocking Queue或Collections.synchronizedList(new LinkedList<>()),我喜欢Collections.synchronized ...因为它有效地使您的收集线程安全,并且您不会对锁和标志感到困扰类似的东西...只是写逻辑可读代码。

LinkedList将为您提供addFirst()addLast()和ofcourse getFirst(),getLast()以实现FIFO或LIFO行为......