我正在使用AMQP对进行图搜索的多个线程进行排队。除了通过单独的线程定期间隔之外,不会修改图形。什么是最好的并发模型,等待所有活动搜索完成,阻止这些线程,并允许更新线程在解锁搜索线程之前修改图形?
我一直在阅读http://docs.oracle.com/javase/tutorial/essential/concurrency/,但我似乎找不到任何完全适合我模特的东西。
有什么建议吗?
谢谢!
编辑:我正在使用ExecutorService来处理线程。
答案 0 :(得分:1)
你真的需要阻止吗?也许非阻塞的写时复制就足够了。
更新线程应该克隆当前图形结构并在克隆上应用更新。完成更新后,应宣布新图表 - 只需覆盖共享参考。
搜索线程应该将图形引用保存到局部变量或范围一次并使用它。永远不会修改共享图,因此不需要任何锁定和等待。
优点:
缺点:
也可以将写时复制仅应用于图形的一部分。特别是如果图形是内存消耗结构。然而,这是一个非常难的主题 - 请参阅MVCC和STM (Software Transactional Memory)。
答案 1 :(得分:0)
我不熟悉AMQP,但这是一个生产者/消费者问题,所以有几种方法可以用Java来解决这个问题。对于Futures和ReentrantLock来说,这是一个非常快速和肮脏的例子:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo {
private static Random rand = new Random();
private static final Lock lock = new ReentrantLock();
private static boolean updating = false;
private static List<Future<Integer>> futureList = new ArrayList<Future<Integer>>();
private static ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
private static Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() {
return rand.nextInt();
}
};
private static void doUpdate() {
if (lock.tryLock()) {
updating = true;
try {
for (Future<Integer> future : futureList) {
System.out.println(future.get());
}
futureList.clear();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println();
lock.unlock();
updating = false;
}
}
}
public static void main(String[] args) throws Exception {
// submitter thread
new Thread(new Runnable() {
@Override
public void run() {
int submitCount = 0;
while (submitCount < 10) {
if (!updating) {
futureList.add(pool.submit(callable));
submitCount++;
}
try {
Thread.sleep(1000); // arbitrary
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
// update thread
new Thread(new Runnable() {
@Override
public void run() {
int updateCount = 0;
while (updateCount < 5) {
doUpdate();
updateCount++;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
我将更新线程设置为提交线程频率的一半。因此,如果你运行它,你会看到更新器每次运行时剥离两个整数。提交线程必须等到更新程序释放锁定。
还有其他方法 - 查看BlockingQueue界面:您可能想要试验。