我正在为Android创建一个媒体播放器应用。我有两个线程:一个产生音频帧,另一个消耗这些帧。
我希望我的客户能够尝试使用不同大小的ArrayBlockedQueue,从“no”缓冲(真正的1)到最多10个缓冲块。
我似乎无法在Java中找到提供与ArrayBlockedQueue类似功能的任何类,但允许我动态地使项目列表更长/更短。
问题1)有没有人知道类似于ArrayBlockedQueue的类,但允许我更改要保留的项目数量?
然后我有一个奇怪的想法:我可以捏造它吗?我可以使用新大小创建一个新的ArrayBlockedQueue,并逐步复制当前在旧ArrayBlockedQueue中的1-10个项目并将它们放入新的ArrayBlockedQueue中,然后将旧指针存储到新的ArrayBlockedQueue上吗? / p>
由于永远不会超过10个(或者我的缓冲区限制),因此将项目复制到新数组时不应花费太多时间。
问题2)这是一种接近ArrayBlockedQueue实现的“合理”方法,仍然具有灵活性吗?
问题3)有没有更好的方法来解决这个问题?
-Ken
答案 0 :(得分:1)
问题:
1)没有一个允许你手动更改队列大小,但是像LinkedBlockingQueue这样的东西增长达到你为它设置的最大值。
2和3)您可以使用文档中描述的第3个构造函数执行您所描述的内容(创建新的ArrayBlockingQueue):
ArrayBlockingQueue(int capacity,boolean fair,Collection c)
创建一个具有给定(固定)容量的ArrayBlockingQueue,指定的访问策略和最初包含给定集合的元素,以集合迭代器的遍历顺序添加。
这为您提供了您正在寻找的复制结构,并允许您设置新容量。评估:
// create the first queue
Queue smallQueue = new ArrayBlockingQueue(5);
// copy small queue over to big queue
Queue bigQueue = new ArrayBlockingQueue(10, false, smallQueue);
缩小尺寸(伪代码):
Queue bigQueue = new ArrayBlockingQueue(10);
// start processing data with your producer / consumer.
// then...
Queue smallQueue = new ArrayBlockingQueue(1);
// 1) change producer to start doing puts into the smallQueue
// 2) let consumer continue consuming from the bigQueue until it is empty
// 3) change consumer to start polling from the smallQueue
来自第1步的投注将会阻止,直到您将消费者转过来。
答案 1 :(得分:1)
您可能需要创建自己的BlockingQueue
实现来包装旧队列和新队列 - 从旧队列轮询直到它为空,然后将其设置为null以防止任何内存泄漏。这样您就不会丢失旧队列中的任何待处理put
MyBlockingQueue {
private MyBlockingQueue oldQueue
private ArrayBlockingQueue newQueue
ArrayBlockingQueue(int newCapacity, MyBlockingQueue _oldQueue) {
oldQueue = _oldQueue
newQueue = new ArrayBlockingQueue(newCapacity)
E oldVal = null
while(newQueue.remainingCapacity() > 0 &&
(oldVal = oldPoll) != null)
newQueue.put(oldVal)
}
boolean isEmpty() {
(oldQueue == null || oldQueue.isEmpty) && newQueue.isEmpty
}
void put(E e) {
newQueue.put(e)
}
E take() {
E oldVal = oldPoll
if(oldVal != null) oldVal else newQueue.take
}
E poll() {
E oldVal = oldPoll
if(oldVal != null) oldVal else newQueue.poll
}
private E oldPoll() {
// If you have more than one consumer thread, then use a temporary variable
// for oldQueue - otherwise it might be set to null between the null check
// and the call to poll
if(oldQueue == null) null
else {
E oldVal = oldQueue.poll
if(oldVal != null) oldVal
else {
oldQueue = null
null
}
}
}
}