17

我想使用 java.util.ConcurrentLinkedQueue 作为 Servlet 的非持久队列。这是该类的 javadoc 中的简介。

基于链接节点的无界线程安全队列。当许多线程将共享对公共集合的访问时,ConcurrentLinkedQueue 是一个合适的选择。此队列不允许空元素。

现在想象一下,我在 servlet 上有 1000 个并发请求,每个线程都需要将一个对象加入到 ConcurrentLinkedQueue 中。从描述中,我是否应该得出结论认为处理负载不会有问题?我需要的保证是:

  1. 我无需自己进行同步即可自动获得线程安全保证。
  2. 如果流量负载超过 1000 个并发请求,我不会丢失任何请求。

谢谢

4

4 回答 4

60

您本质上是在问三个不同的问题(其中两个是明确的,一个是隐含的。)它们是我的答案:

1.如果我使用,我需要自己做同步java.util.ConcurrentLinkedQueue吗?

并发集合上的原子操作会为您同步。换句话说,对队列的每个单独调用都保证是线程安全的,无需您进行任何操作。不能保证线程安全的是您对集合执行的任何非原子操作。

例如,这是线程安全的,您无需执行任何操作:

queue.add(obj);

或者

queue.poll(obj);

然而; 对队列的非原子调用不是自动线程安全的。例如,以下操作不是自动线程安全的:

if(!queue.isEmpty()) {
   queue.poll(obj);
}

最后一个不是线程安全的,因为很有可能在调用 isEmpty 和调用 poll 之间,其他线程会从队列中添加或删除项目。执行此操作的线程安全方式如下:

synchronized(queue) {
    if(!queue.isEmpty()) {
       queue.poll(obj);
    }
}

再次......对队列的原子调用是自动线程安全的。非原子调用不是。

java.util.ConcurrentLinkedQueue2.如果有1000个并发请求,我是否保证不会丢失呼叫?

因为这是一个无限制的实现,你可以保证无论有多少并发请求,队列都不会丢失这些请求(因为队列的并发性......你可能会用完内存或类似......但是队列实现本身不会成为您的限制因素。)在 Web 应用程序中,还有其他机会“丢失”请求,但队列的同步(或缺乏同步)不会成为您的原因。

3.java.util.ConcurrentLinkedQueue表现是否足够好?

通常,当我们谈论并发时,我们会谈论“正确性”。我的意思是,并发类保证它们是线程安全的(或者对死锁、饥饿等具有鲁棒性)。当我们谈论这个时,我们并没有对性能做出任何保证(对集合的调用速度有多快)是)——我们只保证它们是“正确的”。

然而; ConcurrentLinkedQueue 是一个“无等待”的实现,所以这可能是你可以获得的性能。保证 servlet 的负载性能(包括使用并发类)的唯一方法是在负载下对其进行测试。

于 2009-01-12T16:20:52.570 回答
3

请记住,队列仅对单个成员的调用是线程安全的。不要编写这样的代码并期望它能够工作:

if (queue.Count!=0)
    queue.Dequeue().DoSomething();

在这两个操作之间,另一个线程可能已将最后一个元素出队。我对 Java 集合并不熟悉,但我猜 Dequeue 在这种情况下会返回null,给你一个例外。

于 2009-01-12T11:01:12.653 回答
1
  1. 由于队列是线程安全的,因此您不需要执行任何同步来确保线程安全。但是,您应该确保所有线程都可以平等地访问队列,以避免饥饿、忙等待等......

  2. 由于队列是无界的,队列的大小仅受可用内存量的限制。

于 2009-01-12T10:52:35.683 回答
0

是的,对于你的两个问题。

并发队列线程安全的(并且由于下面使用的无块算法而高效)。线程安全 意味着并发访问的数量不能有任何区别(我还没有听说过保证不会在 xyz 并发访问以下发生的竞争条件)。

除此之外——多线程应用程序中的最佳性能比这更复杂。但是使用真正的并发集合并不是一个糟糕的开始。

于 2009-01-12T10:59:53.170 回答