我已经用Java编程了一段时间,但对并发编程很新,所以请耐心等待!
我正在尝试开发一个包含一组Collection类[例如ArrayLists]的类,然后找到一个指定的值,它同时遍历所有集合,如果找到给定的值就停止所有线程。
我已经粘贴了下面的代码,并且想知道是否有人知道如果其中一个返回Futures的线程返回true,那么我在catch_multiple_collections()中如何捕获?
由于
格雷厄姆
public class CollectionGroup<V> extends ContainerGroup
{
//...
public boolean contains(V value)
{
boolean containsValue = false;
if (mCollections.size() == 1)
{
containsValue = mCollections.get(0).contains(value);
}
else
{
containsValue = contains_multiple_collections(value);
}
return containsValue;
}
private boolean contains_multiple_collections(V value)
{
// thread pool
int numberProcessors = mCollections.size();
ExecutorService es = Executors.newFixedThreadPool(numberProcessors);
for (int i=0; i<numberProcessors; i++)
{
AbstractCollection<V> collection = mCollections.get(i);
MyCallable callable = new MyCallable(collection,value);
Future<Boolean> future = es.submit(callable);
//...
}
return true;
}
private class MyCallable implements Callable<Boolean>
{
protected AbstractCollection<V> mCollection;
protected V mValue;
public MyCallable(AbstractCollection<V> collection, V value)
{
mCollection = collection;
mValue = value;
}
@Override
public Boolean call() throws Exception
{
boolean ok = mCollection.contains(mValue);
return ok;
}
} // class MyCallable
} // class CollectionGroup
答案 0 :(得分:2)
包含不会因为您可能在另一个线程中找到该值而停止。唯一的方法就是循环自己。
对于CPU密集型进程,最佳线程数可能是您拥有的核心数。创建太多线程会增加开销,从而减慢解决方案的速度。
你应该记得在完成它后关闭()ExecutorService。
如果你想加快搜索速度,我会保持一组所有值,这可能比使用多个线程快10-100倍。
答案 1 :(得分:1)
您可以使用ExecutorCompletionService。只需保持take()ing(take()块直到完成的Future存在),直到得到结果为true,并在找到某些东西后将shutdownNow()作为底层的ExecturService。一旦找到值,这不会立即停止所有线程。
答案 2 :(得分:0)
您可以反复遍历所有期货并使用get进行轮询,使用零或几乎为零的超时,但可能更好的想法是为所有MyCallable
提供回调,这应该是然后在找到匹配时调用它。然后,回调应该取消所有其他任务,可能是关闭ExecutorService
。
答案 3 :(得分:0)
我建议使用静态AtomicBoolean,它在找到匹配项时设置。然后,每个线程都可以在继续之前检查该值。
答案 4 :(得分:0)
问题是您的contains_multiple_collections方法不会等待搜索完成。你有两个我能想到的选择。第一个涉及一些异步回调实现,其中contains方法不会阻塞,并且可能将回调/侦听器对象作为参数。第二种是制作包含方法块,直到确定结果为止。我已经为下面的方法概述了一个示例实现,它没有经过测试所以要小心......
/*
* contains_multiple_collections now blocks until the desired
* value is located or all searches have completed unsuccessfully...
*/
private boolean contains_multiple_collections(V value) {
// thread pool
int numberProcessors = mCollections.size();
ExecutorService es = Executors.newFixedThreadPool(numberProcessors);
Object lock = new Object();
AtomicBoolean outcome = new AtomicBoolean(false);
AtomicInteger remainingSearches = new AtomicInteger(mCollections.size());
for (int i = 0; i < numberProcessors; i++) {
AbstractCollection<V> collection = mCollections.get(i);
es.submit(new MyRunnable(collection, value, lock, outcome, remainingSearches));
}
/* Wait for searches to run. This thread will be notified when all searches
* complete without successfully locating the value or as soon as the
* desired value is found.
*/
synchronized (lock) {
while (!outcome.get() && remainingSearches.get() > 0) {
try {
lock.wait();
} catch (InterruptedException ex) {
// do something sensible.
}
}
es.shutdownNow();
}
return outcome.get();
}
private class MyRunnable implements Runnable {
final AbstractCollection<V> mCollection;
final V mValue;
final Object lock;
final AtomicBoolean outcome;
final AtomicInteger remainingSearches;
public MyRunnable(AbstractCollection<V> mCollection, V mValue,
Object lock, AtomicBoolean outcome, AtomicInteger remainingSearches) {
this.mCollection = mCollection;
this.mValue = mValue;
this.lock = lock;
this.outcome = outcome;
this.remainingSearches = remainingSearches;
}
public void run() {
boolean ok = mCollection.contains(mValue);
if (ok || remainingSearches.decrementAndGet() == 0) {
synchronized (lock) {
if (ok) {
outcome.set(true);
}
lock.notify();
}
}
}
}