I have a list containing the data to calculate for each pixel (e.g. list size = 1024x768). Now I want to repeat the multithreading in the list and save the calculation for each pixel in the HashMap. But no matter what I do, I cannot do everything right. I tried several ways, my last was the following:
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(); }
Note that hasNext() iterators hasNext() synchronized. The problem is sometimes related to the heap problem or simply that the HashMap is smaller than the size of the list.
I assume that I did not understand something about the proper execution of Runnables or ExecutorService.
I appreciate any help here.
EDIT: I added System.out.println(i) immediately before the i++ statement. Despite the fact that at some point i < 1000 unexpectedly detected, the following appears:
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)
EDIT 2: According to Warst's answer, I tried the following
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(); } }
But it is very strange that the Runnable block is never entered, why?