设计 - 只在虚拟机上运行一个线程

时间:2014-05-24 11:56:36

标签: java multithreading

在接受采访时提到了这个问题。

有多个虚拟机(JVM)。有N个线程完全运行。 N'GT; = M

如何确保在所有VM中只运行一个线程。在该线程完成其任务后,另一个线程将有机会运行。

4 个答案:

答案 0 :(得分:3)

摘要

基本上你要找的是分布式锁。一次一个线程将能够获取分布式锁并继续。大多数真正的分布式系统通常需要不时地相互协调,并且有许多记录的分布式锁定算法。

纯Java解决方案:

您可以直接通过套接字与其他进程通信,也可以使用多播向所有侦听服务广播。 Java有一个很好的socket api,所以这是合理的。您可以使用类似RMI的东西并让一个线程充当协调器。或者使用类似八卦协议的东西来协调Cassandra。

我会做什么:

假设您被允许在流程之外需要其他服务。我会用Zookeeper。 Zookeeper是一个与语言无关的Apache项目,专为分布式协调而设计,并被许多分布式系统(如Kafka)大量使用。

在Zoo wiki

中描述了在Zookeeper中实现分布式锁

那么你需要做的就是在你的N个线程中让他们按照获取分布式锁的配方,然后只有其中一个会一次通过协调障碍。

讨论:

你可能已经注意到这些解决方案都是从假设许多线程可以畅通无阻地运行开始,直到他们协调并同意轮流进行。如果你希望只有一个最接近你可能得到的命令行参数就像--coordinator一样,只将它传递给一个实例,并将协调器的IP和端口提供给所有其他实例,这样它们就可以了可以ping它并请求运行权限。协调员可以像一个请求队列一样简单,它将依次响应。即使这一个进程产生了许多线程,你也可以将其中一个作为协调器进行分类,并且任何没有协调器标志的设置都会立即通过你选择的任何方法从协调器进行回调,无论是套接字,消息队列Zookeeper还是其他什么完全。

答案 1 :(得分:0)

如果您要求每个JVM使用一个线程。 Alécio的回答应该已经足够了。如果你要求跨越JVM的一个线程,你将不得不使用某种形式的IPC,我更喜欢使用Chronicle,这是Peter Lawrey的一个很棒的库。但无论如何,对于“跨越所有虚拟机的唯一一个应用程序线程”,您将没有非常严格的保证“

答案 2 :(得分:-1)

在单个VM 中,您可以创建“单线程执行程序”,Java在执行程序类上提供了这样的东西:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor()

但是你可以根据需要创建自己的Executor,例如..生成一个接收Runnable要执行的Singleton类,你可以在内部将这个Runnable入队,这将被'循环'所占用你自己的,将一个接一个地调用'run()'方法。像这样,您确保一次只运行一个作业。

对于跨VM 解决方案,您可能必须依赖于特定的应用程序服务器解决方案,可能WildFly(以前称为 JBoss )提供此类功能

答案 3 :(得分:-1)

让每个线程获取一个独占数据库锁,例如通过" select for update"在运行任务之前进行查询,然后释放锁。