繁体   English   中英

寻找Java并发模型建议

[英]looking for java concurrency model suggestion

我正在使用AMQP将多个线程排队进行图搜索。 除非通过单独的线程按固定间隔进行修改,否则该图不会被修改。 什么是最好的并发模型来等待所有活动搜索完成,阻止那些线程并允许更新线程在取消阻止搜索线程之前修改图形?

我一直在阅读http://docs.oracle.com/javase/tutorial/essential/concurrency/,但似乎找不到与我的模型完全相符的内容。

有什么建议么?

谢谢!

编辑:我正在使用ExecutorService处理线程。

您真的需要阻止吗? 也许无阻塞的写时复制就足够了。

更新线程应制作一个当前图形结构的副本,并在该副本上应用更新。 完成更新后,应宣布新图形-只是覆盖共享引用。

搜索线程应将图形引用保存到局部变量或范围一次并使用它。 共享图永远不会被修改,因此不需要任何锁定和等待。

优点:

  • 没有锁定和等待读者,
  • 如果更新失败,读者仍然可以使用旧结构
  • 非常适合长时间运行和偶尔的更新,其中读取多于更新
  • 垃圾收集器负责处理旧图

缺点:

  • 如果某些读者在更新之前就开始使用旧数据,则可能会对其进行操作-通过检查图形的原始引用是否已更改并最终重新启动整个操作,可以解决此问题。
  • 多个作者可能会在图中引入冲突,但是可以通过几种冲突解决方法来解决,最简单的方法就是忽略先前的更改并覆盖(“ Take mine”)。

也可以仅将写时复制应用于图的一部分。 尤其是当图形是内存消耗结构时。 但是,这是一个很难的话题-请参阅MVCCSTM(软件事务存储)

我不熟悉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接口:您可能想尝试一下。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM