Java Executorservice和Runnable
我有一个列表,其中包含每个像素要计算的数据(例如,列表大小=1024x768)。现在我想在列表中迭代多线程,并将每个像素的计算结果保存在HashMap中。但无论我做什么,我都无法做到正确。我尝试了几种方法,最后一种是:Java Executorservice和Runnable,java,Java,我有一个列表,其中包含每个像素要计算的数据(例如,列表大小=1024x768)。现在我想在列表中迭代多线程,并将每个像素的计算结果保存在HashMap中。但无论我做什么,我都无法做到正确。我尝试了几种方法,最后一种是: ConcurrentMap<T, Color> map = new ConcurrentHashMap<T, Color>(); ExecutorService pool = Executors.newFixedThrea
ConcurrentMap<T, Color> map = new ConcurrentHashMap<T, Color>();
ExecutorService pool = Executors.newFixedThreadPool(4);
Iterator<T> it = camera.iterator();
while (it.hasNext()) {
Runnable run = () -> {
int i = 0;
while (it.hasNext() && i < 1000) {
i++;
T cameraRay = it.next();
if (object.collide(cameraRay.getRay()) == null)
map.put(cameraRay, BG_COLOR);
else
map.put(cameraRay, this.shader.shade(cameraRay.getRay(), object.collide(cameraRay.getRay())).getColor());
}
};
pool.execute(run);
}
pool.shutdown();
try {
if (pool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS)) {
System.out.println("Mapsize: " + map.size());
// Draw Image:
map.forEach((ray, color) -> {image.setColor(ray, color);});
}
} catch (InterruptedException e) {
e.printStackTrace();
}
编辑2:
根据沃克斯特的回答,我尝试了以下方法
Iterator<T> it = camera.iterator();
List<T> buffer = new ArrayList<T>(1000);
while (it.hasNext()) {
buffer.add(it.next());
if (buffer.size() >= 1000 || !it.hasNext()) {
Runnable run = () -> {
for (T cameraRay : buffer) {
if (object.collide(cameraRay.getRay()) == null) // No collision
map.put(cameraRay, BG_COLOR);
else
map.put(cameraRay, this.shader.shade(cameraRay.getRay(), object.collide(cameraRay.getRay())).getColor());
}
};
pool.execute(run);
buffer.clear();
}
}
Iterator it=camera.Iterator();
列表缓冲区=新的ArrayList(1000);
while(it.hasNext()){
add(it.next());
if(buffer.size()>=1000 | |!it.hasNext()){
可运行运行运行=()->{
用于(T摄影机阵列:缓冲区){
if(object.collide(cameraRay.getRay())==null)//无冲突
地图放置(照相机,背景颜色);
其他的
map.put(cameraRay,this.shader.shade(cameraRay.getRay(),object.collide(cameraRay.getRay()).getColor());
}
};
pool.execute(run);
buffer.clear();
}
}
但非常奇怪的是,
Runnable
块现在从未被输入,为什么?让我困惑的是,您的Runnable都使用相同的迭代器。更让我惊讶的是,您在迭代迭代器时生成了runnables,但这些runnables也操纵迭代器。这段代码可能(并且将会,正如你的问题所证明的那样)导致一系列的竞争条件和随之而来的头痛问题
我建议如下:
507
169
86624
625
626
Exception in thread "pool-2-thread-2" java.lang.OutOfMemoryError: Java heap space
Exception in thread "pool-2-thread-3" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(Unknown Source)
at com.sun.javafx.application.LauncherImpl.launchApplication(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.launcher.LauncherHelper$FXHelper.main(Unknown Source)
Caused by: java.lang.OutOfMemoryError: Java heap space
at java.util.concurrent.ThreadPoolExecutor.addWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)
at raytracer.impl.ParallelRenderer.render(ParallelRenderer.java:78)
at raytracer.ImageViewer.main(ImageViewer.java:118)
... 11 more
Exception in thread "pool-2-thread-4" java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: Java heap space
at raytracer.impl.TriangleImpl.collide(TriangleImpl.java:87)
at raytracer.impl.SimpleScene.collide(SimpleScene.java:27)
at raytracer.impl.ParallelRenderer.lambda$0(ParallelRenderer.java:71)
at raytracer.impl.ParallelRenderer$$Lambda$48/24559708.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
public static void main(String[] args) throws InterruptedException {
ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>();
ExecutorService pool = Executors.newFixedThreadPool(4);
Iterator<Integer> it = getIt();
Task t = new Task(map);
while (it.hasNext()) {
t.add(it.next());
if (t.size()>=1000 || !it.hasNext()) {
pool.submit(t);
t = new Task(map);
}
}
pool.shutdown();
pool.awaitTermination(1, TimeUnit.DAYS);
// Breakpoint here to inspect map
System.out.println("Done!");
}
publicstaticvoidmain(String[]args)抛出InterruptedException{
ConcurrentHashMap=新的ConcurrentHashMap();
ExecutorService池=Executors.newFixedThreadPool(4);
迭代器it=getIt();
任务t=新任务(map);
while(it.hasNext()){
t、 添加(it.next());
如果(t.size()>=1000 | |!it.hasNext()){
提交(t);
t=新任务(map);
}
}
pool.shutdown();
池终止(1,时间单位:天);
//此处的断点用于检查映射
System.out.println(“完成!”);
}
与
private静态迭代器getIt(){
返回新的迭代器(){
私有整数nr=0;
@凌驾
公共布尔hasNext(){
返回nr<20000;
}
@凌驾
公共整数next(){
返回nr++;
}
};
}
及
私有静态类任务扩展ArrayList实现可运行{
私有最终ConcurrentHashMap映射;
公共任务(ConcurrentHashMap映射){
this.map=map;
}
@凌驾
公开募捐{
试一试{
for(整数i:此){
//模拟一些压缩:每个数字在10次迭代中写入stdout:每个Runnable需要10000次打印
对于(int j=0;j<10;j++){
System.out.println(“迭代”+j+”表示“+i”);
}
//在映射中存储一些东西,即这个整数,在您的例子中是T,已经被处理过了
地图。放置(i,“完成”);
}
}捕获(例外e){
e、 printStackTrace();
}
}
}
大约20-30秒后到达断点,映射包含与字符串“Done”配对的所有整数
迭代器的next()方法是否同步?您认为是否有可能使用java 8流?n2()不同步,因为这是一个决定方法签名的练习。而且它还明确声称使用ExecutorService…T的类型是什么?变量名为
cameraRay
。它是一个大物体还是一个很小的物体?它是否正确实现了hashCode()
和equals()
?@Magnamag它非常小,由两个3d向量和两个像素坐标整数组成。我想hashCode()
和equals()
可以正常工作,因为使用顺序渲染器一切都很好。@Rafael有两个3d向量+坐标。。。这最多是8个整数。每个int
需要4
字节,因此每个T至少是32
字节。如果您有1024*768=786432
Ts,则只有地图的键最多占用~25 mb
。我不是说你应该因为25MB的内存而耗尽内存,只是试着理解数字。颜色怎么样?它是大的还是小的?我做了一个编辑试图实现你的建议。注意:我无法创建t的通用数组(t[]buffer=new t[1000];
)啊,对了,您无法创建通用数组。尝试使用任何集合,例如ArrayList
作为缓冲区<代码>ArrayList缓冲区=新建ArrayList()代码>。我在您的代码片段中看到,您对所有可运行程序重用了缓冲区。不要!为提交的每个runnable创建一个新的ArrayList。否则,您将在所有线程之间有效地共享一个集合。事实上,大多数代码看起来都很奇怪。我会编一个例子并更新我的答案。谢谢你的努力。你的例子也不起作用。最后,当执行所有任务时,map.size()
为0。此外,您的帮助类需要位于方法(名为render(object,camera,image)
)中,并且缺少泛型类型(Task
)。但考虑到所有这些,每次都是一张空地图和等待
private static Iterator<Integer> getIt(){
return new Iterator<Integer>() {
private int nr = 0;
@Override
public boolean hasNext() {
return nr < 20000;
}
@Override
public Integer next() {
return nr++;
}
};
}
private static class Task extends ArrayList<Integer> implements Runnable{
private final ConcurrentHashMap<Integer, String> map;
public Task(ConcurrentHashMap<Integer, String> map) {
this.map = map;
}
@Override
public void run() {
try{
for (Integer i : this) {
// Simulate some crunching: write to the stdout in 10 iterations for each number: 10 000 prints for each Runnable
for (int j = 0; j < 10; j++) {
System.out.println("Iteration "+j+" for "+i);
}
// Store something in the map, namely that this Integer, or T in your case, has been processed
map.put(i, "Done");
}
} catch(Exception e){
e.printStackTrace();
}
}
}