0

我需要一个集合来存储来自许多客户端的大量请求,同时我使用一个线程处理每五秒存储一次的所有请求。那么我应该在 java 中选择哪个集合以获得最佳效率?显然,集合应该是线程安全的,并且每五秒轮询一次所有元素的效率,对吧?

4

3 回答 3

4

在这种情况下,您可以尝试使用ArrayBlockingQueue 。

由数组支持的有界阻塞队列。此队列对元素进行 FIFO(先进先出)排序。队列的头部是在队列中时间最长的元素。队列的尾部是在队列中时间最短的元素。新元素被插入到队列的尾部,队列检索操作获取队列头部的元素。

这是一个经典的“有界缓冲区”,其中一个固定大小的数组保存由生产者插入并由消费者提取的元素。一旦创建,容量将无法更改。尝试将元素放入完整队列将导致操作阻塞;尝试从空队列中获取元素同样会阻塞。

这里有一个take方法,它会阻塞而不消耗 CPU 周期,直到一个项目被添加到队列中。它是线程安全的。

于 2013-10-23T14:12:59.040 回答
1

DoubleBufferedList我为这种情况写了一个无锁的。本质上,您可以从多个线程对其进行写入,并且写入会累积。当读取出现时,将返回整个列表,同时以线程安全的方式创建一个新列表供写入者写入。

这与任何类型之间的关键区别在于BlockingQueueQueue您需要一次轮询每个条目。这种结构一次性为您提供了整个累积列表,其中包含自上次查看以来累积的所有内容。

public class DoubleBufferedList<T> {
  // Atomic reference so I can atomically swap it through.
  // Mark = true means I am adding to it so momentarily unavailable for iteration.
  private AtomicMarkableReference<List<T>> list = new AtomicMarkableReference<>(newList(), false);

  // Factory method to create a new list - may be best to abstract this.
  protected List<T> newList() {
    return new ArrayList<>();
  }

  // Get and replace with empty the current list - can return null - does not mean failed.
  public List<T> get() {
    // Atomically grab and replace the list with an empty one.
    List<T> empty = newList();
    List<T> it;
    // Replace an unmarked list with an empty one.
    if (!list.compareAndSet(it = list.getReference(), empty, false, false)) {
      // Failed to replace! 
      // It is probably marked as being appended to but may have been replaced by another thread.
      // Return empty and come back again soon.
      return Collections.<T>emptyList();
    }
    // Successfull replaced an unmarked list with an empty list!
    return it;
  }

  // Grab and lock the list in preparation for append.
  private List<T> grab() {
    List<T> it;
    // We cannot fail so spin on get and mark.
    while (!list.compareAndSet(it = list.getReference(), it, false, true)) {
      // Spin on mark - waiting for another grabber to release (which it must).
    }
    return it;
  }

  // Release the list.
  private void release(List<T> it) {
    // Unmark it - should this be a compareAndSet(it, it, true, false)?
    if (!list.attemptMark(it, false)) {
      // Should never fail because once marked it will not be replaced.
      throw new IllegalMonitorStateException("It changed while we were adding to it!");
    }
  }

  // Add an entry to the list.
  public void add(T entry) {
    List<T> it = grab();
    try {
      // Successfully marked! Add my new entry.
      it.add(entry);
    } finally {
      // Always release after a grab.
      release(it);
    }
  }

  // Add many entries to the list.
  public void add(List<T> entries) {
    List<T> it = grab();
    try {
      // Successfully marked! Add my new entries.
      it.addAll(entries);
    } finally {
      // Always release after a grab.
      release(it);
    }
  }

  // Add a number of entries.
  @SafeVarargs
  public final void add(T... entries) {
    // Make a list of them.
    add(Arrays.<T>asList(entries));
  }

}
于 2013-10-23T14:35:38.967 回答
0

我的建议是使用时间戳作为键、请求对象作为值的静态 ConcurrentHashmap。

于 2013-10-23T14:11:37.853 回答