我刚刚开始使用java,很抱歉,如果这个问题的答案很明显。我无法弄清楚如何在java中共享变量。我一直在使用python,并希望尝试将一些代码移植到Java以更好地学习语言。很多我的代码被移植但我不确定多少处理和变量共享在Java中是如何工作的(我的进程不受磁盘限制,并且使用了大量的cpu和搜索列表)。
在Python中,我可以这样做:
from multiprocessing import Pool, Manager
manager = Manager()
shared_list = manager.list()
pool = Pool(process=4)
for variables_to_send in list_of_data_to_process:
pool.apply_async(function_or_class, (variables_to_send, shared_list))
pool.close()
pool.join()
我在查找如何在Java中进行多处理和共享时遇到了一些麻烦。这个question帮助我理解了一下(通过代码)实现runnable如何帮助我开始认为java可能会自动多处理线程(如果我错了就纠正我,我读到一旦线程超过容量一个cpu他们被转移到另一个CPU?oracle文档似乎更专注于线程而不是多处理)。但它没有解释如何在进程之间共享列表或其他变量(并使它们保持足够接近的同步)。
有任何建议或资源吗?我希望我正在寻找错误的东西(多处理java),并希望这与我上面的代码一样容易(或类似简单)。
谢谢!
答案 0 :(得分:3)
线程和进程之间存在重要差异,您现在正在遇到它:除了一些例外情况,线程共享内存,但进程不会。
请注意,真正的操作系统可以解决我即将要说的所有内容,但在典型情况下不会使用这些功能。因此,要启动一个新进程,必须使用系统调用以某种方式克隆当前进程(在* nix上,这是fork()
),然后替换代码,堆栈,命令行参数等带有另一个系统调用的子进程的调用(在* nix上,这是exec()
系列调用)。 Windows与这两个系统调用大致相同,所以我所说的一切都是跨平台的。此外,Java Runtime Environment负责所有这些系统调用,如果没有JNI或其他一些互操作技术,您无法自己真正执行它们。
有关此模型的两个重要注意事项:子进程不共享父进程的地址空间,并且exec()
调用将替换子进程的整个地址空间。因此,父进程中的变量对子进程不可用,反之亦然。
线程模型完全不同。线程有点像精简进程,因为每个线程都有自己的指令指针,并且(在大多数系统上)线程由操作系统调度程序调度。但是,线程是进程的一部分。每个进程至少有一个线程,进程中的所有线程共享内存。
现在问题:
Python代理示例显示,Python多处理模块只需很少的工作即可生成进程。在Java中,产生一个新进程需要更多的工作。它涉及使用Process或ProcessBuilder.start()创建新的Runtime.exec()对象。然后,您可以将字符串传递给子进程,获取其输出,等待它退出,以及一些其他通信原语。我建议编写一个程序作为协调员并启动每个子进程,并编写一个大致对应于示例中function_or_class
的工作程序。协调员可以打开工作程序的多个副本,为每个工作程序分配任务,并等待所有工作人员完成。
答案 1 :(得分:1)
您可以将Java Thread用于此目的。您需要创建一个用户定义的类。该类应该有setter方法,您可以通过它设置shared_list对象。实现Runnable接口并在run()方法中执行处理任务。你可以在互联网上找到很好的例子。如果要共享同一个shared_list实例,则需要确保同步对此变量的访问。
答案 2 :(得分:1)
这不是在java中使用线程的最简单方法,但它对你发布的python代码是封闭的。任务类是可调用接口的实例,它有一个调用方法。当我们创建10000个Task实例中的每一个时,我们将它们传递给同一个列表。因此,当调用所有这些对象的调用方法时,它们将使用相同的列表。
我们在这里使用固定大小的4个线程的线程池,因此我们提交的所有任务都会排队等待线程可用。
public class SharedListRunner {
public void RunList() {
ExecutorService executerService = Executors.newFixedThreadPool(4);
List<String> sharedList = new List<String>();
sharedList.add("Hello");
for(int i=0; i < 10000; i++)
executerService.submit(new Task(list));
}
}
public class Task implements Callable<String> {
List<String> sharedList;
public Task(List<String> sharedList) {
this.sharedList = sharedList;
}
@Override
public String call() throws Exception {
//Do something to shared list
sharedList.size();
return "World";
}
}
在任何时候,4个线程都在访问列表。如果你想进一步挖掘4个Java线程正在访问列表,那么为这4个java线程提供服务的操作系统线程可能更少,而且每个CPU的核心通常有2个或4个更少的处理器线程。