我需要一个集合来存储来自许多客户端的大量请求,同时我使用一个线程处理每五秒存储一次的所有请求。那么我应该在 java 中选择哪个集合以获得最佳效率?显然,集合应该是线程安全的,并且每五秒轮询一次所有元素的效率,对吧?
问问题
152 次
3 回答
4
在这种情况下,您可以尝试使用ArrayBlockingQueue 。
由数组支持的有界阻塞队列。此队列对元素进行 FIFO(先进先出)排序。队列的头部是在队列中时间最长的元素。队列的尾部是在队列中时间最短的元素。新元素被插入到队列的尾部,队列检索操作获取队列头部的元素。
这是一个经典的“有界缓冲区”,其中一个固定大小的数组保存由生产者插入并由消费者提取的元素。一旦创建,容量将无法更改。尝试将元素放入完整队列将导致操作阻塞;尝试从空队列中获取元素同样会阻塞。
这里有一个take方法,它会阻塞而不消耗 CPU 周期,直到一个项目被添加到队列中。它是线程安全的。
于 2013-10-23T14:12:59.040 回答
1
DoubleBufferedList
我为这种情况写了一个无锁的。本质上,您可以从多个线程对其进行写入,并且写入会累积。当读取出现时,将返回整个列表,同时以线程安全的方式创建一个新列表供写入者写入。
这与任何类型之间的关键区别在于BlockingQueue
,Queue
您需要一次轮询每个条目。这种结构一次性为您提供了整个累积列表,其中包含自上次查看以来累积的所有内容。
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 回答