0

我有以下关于 Java 7 ConcurrentLinkedQueue 的问题。让我们假设我有以下课程:

public class Blah {
    private ConcurrentLinkedQueue<String> queue;

    public Blah() {
        queue = new ConcurrentLinkedQueue<String>();
    }

    public void produce(String action, String task) throws InterruptedException {
        synchronized(queue) {
            while(queue.size() >= 8) 
                queue.wait();
            queue.add(action + "#" + task);
            queue.notifyAll();
        }
    }

    public void consume() throws InterruptedException {
        synchronized(queue) {
            while(queue.size() <= 0)
                queue.wait();
            String element = queue.poll();
            StringTokenizer strTok = new StringTokenizer(element, "#");
            String action = strTok.nextToken();
            String task = strTok.nextToken();
            /**
             * Operate on request
             */
            queue.notifyAll();
        }
    }
}

并发线程将调用生产和消费函数,以便为列表/从列表中生成/删除线程。我实现了前面的函数consume() 和produce(),以便序列化队列中元素的添加/删除。以上是必需的,还是 ConcurrentLinkedQueue 负责?我问是因为我不想降低代码的性能。

谢谢你,尼克

4

3 回答 3

1

您确实降低了代码的性能,因为您使用的是同步机制中“最慢”的内置同步。

你有一个完美的用例BlockingQueue。它为您提供了在空间/元素可用之前阻塞的操作puttake

ConcurrentLinkedQueue只为您提供线程安全而不是同步。这意味着您可以在多线程应用程序中安全地从队列中添加/删除元素,但它没有为您提供等待空间/元素的机制,因此您正确地使用了 wait()、notify() 方法(尽管您可以在任何其他共享对象上也同步,它不必是那个队列)。在 Java 中使用 Lock 而不是 synchronized 更快。

于 2015-04-12T22:10:24.977 回答
1

TL;DR:您正在使用Queue专门设计为非阻塞的BlockingQueue.

您的代码可以重写为:

public class Blah {
    private BlockingQueue<String> queue;

    public Blah() {
        queue = new LinkedBlockingQueue<>(8);
    }

    public void produce(String action, String task) throws InterruptedException {
        while (true) {
            queue.put(action + "#" + task);
        }
    }

    public void consume() throws InterruptedException {
        while (true) {
            final String[] data = queue.take().split("#");
            final String action = data[0];
            final String task = data[1];
        }
    }
}

以元素BlockingQueue为界。如果队列已满,将阻塞。如果队列为空,将阻塞。8puttake

不需要同步。

此外,StringTokenizer已弃用。我建议你使用类似的class东西:

public class Data {
    private final String action;
    private final String task;

    public Data(final String action, final String task) {
        this.action = action;
        this.task = task;
    }

    public String getAction() {
        return action;
    }

    public String getTask() {
        return task;
    }
}

交换数据。没有理由创建和解析Strings。

于 2015-04-12T22:38:13.517 回答
-2

假设produceandconsume将被独立调用,您可能会以无限循环结束,因为两者都试图锁定队列对象,因此一旦consume找不到任何元素,它将永远不会释放锁定,从而阻止生产者添加元素。同步逻辑可能应该在调用consume和的方法中实现produce

于 2015-04-12T22:17:00.397 回答