我想将元组对象存储在并发 java 集合中,然后有一个高效的阻塞查询方法,该方法返回第一个与模式匹配的元素。如果没有这样的元素可用,它将阻塞直到出现这样的元素。
例如,如果我有一个类:
public class Pair {
public final String first;
public final String Second;
public Pair( String first, String second ) {
this.first = first;
this.second = second;
}
}
还有一个像这样的集合:
public class FunkyCollection {
public void add( Pair p ) { /* ... */ }
public Pair get( Pair p ) { /* ... */ }
}
我想这样查询:
myFunkyCollection.get( new Pair( null, "foo" ) );
它返回第一个可用的对,其中 second
字段等于“foo”或 block ,直到添加这样的元素。另一个查询示例:
myFunkyCollection.get( new Pair( null, null ) );
应该返回第一个可用的对,无论它的值是什么。
是否已经存在解决方案?如果不是这种情况,您建议如何实现 get( Pair p )
方法?
说明: get( Pair p)
方法还必须移除元素。名字的选择不是很聪明。更好的名称是 take( ... )
。
最佳答案
这是一些源代码。它与 cb160 所说的基本相同,但是拥有源代码可能有助于清除您可能仍然存在的任何问题。特别是 FunkyCollection 上的方法必须同步。
正如 meriton 指出的那样,每次添加新对象时,get 方法都会对每个阻塞的 get 执行 O(n) 扫描。它还执行 O(n) 操作来删除对象。这可以通过使用类似于链接列表的数据结构来改进,您可以在其中将迭代器保留到最后检查的项目。我没有提供此优化的源代码,但如果您需要额外的性能,实现起来应该不会太困难。
import java.util.*;
public class BlockingQueries
{
public class Pair
{
public final String first;
public final String second;
public Pair(String first, String second)
{
this.first = first;
this.second = second;
}
}
public class FunkyCollection
{
final ArrayList<Pair> pairs = new ArrayList<Pair>();
public synchronized void add( Pair p )
{
pairs.add(p);
notifyAll();
}
public synchronized Pair get( Pair p ) throws InterruptedException
{
while (true)
{
for (Iterator<Pair> i = pairs.iterator(); i.hasNext(); )
{
Pair pair = i.next();
boolean firstOk = p.first == null || p.first.equals(pair.first);
boolean secondOk = p.second == null || p.second.equals(pair.second);
if (firstOk && secondOk)
{
i.remove();
return pair;
}
}
wait();
}
}
}
class Producer implements Runnable
{
private FunkyCollection funkyCollection;
public Producer(FunkyCollection funkyCollection)
{
this.funkyCollection = funkyCollection;
}
public void run()
{
try
{
for (int i = 0; i < 10; ++i)
{
System.out.println("Adding item " + i);
funkyCollection.add(new Pair("foo" + i, "bar" + i));
Thread.sleep(1000);
}
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
}
}
public void go() throws InterruptedException
{
FunkyCollection funkyCollection = new FunkyCollection();
new Thread(new Producer(funkyCollection)).start();
System.out.println("Fetching bar5.");
funkyCollection.get(new Pair(null, "bar5"));
System.out.println("Fetching foo2.");
funkyCollection.get(new Pair("foo2", null));
System.out.println("Fetching foo8, bar8");
funkyCollection.get(new Pair("foo8", "bar8"));
System.out.println("Finished.");
}
public static void main(String[] args) throws InterruptedException
{
new BlockingQueries().go();
}
}
输出:
Fetching bar5.
Adding item 0
Adding item 1
Adding item 2
Adding item 3
Adding item 4
Adding item 5
Fetching foo2.
Fetching foo8, bar8
Adding item 6
Adding item 7
Adding item 8
Finished.
Adding item 9
请注意,我将所有内容都放在一个源文件中以使其更易于运行。
关于java - 有效阻塞查询的建议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2035282/