Java - Multithreading with ImageIO

≡放荡痞女 提交于 2019-12-08 04:16:33

问题


I have a program that loads slowly, which I guess is due to the amount of image resources I have to load at the beginning. I thought multi-threading would help, but now I'm not so sure. Here is my automatic multi-threading method.

    private static Thread[] t;

    private static int currentThreads;

    public static void loadWithThreads(Object[] array, IntegerRunnable r) {

        final int threads =  Runtime.getRuntime().availableProcessors();
        t = new Thread[threads];

        for (int i = 0; i < threads; i ++) {
            t[i] = new Thread("HMediaConverter") {

                final int id = currentThreads;

                int items = (array.length / threads) * currentThreads;


                @Override
                public void run() {

                    super.run();

                    for (int i = items; i < (items + (array.length / threads)); i ++) {
                        r.run(i);
                    }

                    //Recycle this thread so it can be used for another time.
                    try {
                        t[id].join();
                        lock.notifyAll();
                        currentThreads --;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }


            };
            t[i].setPriority(Thread.MAX_PRIORITY);
            t[i].start();
            currentThreads ++;
        }
    }

And here is my image loading code:

public static ImageIcon loadImageIcon(String path) {
    return new ImageIcon(ImageIO.read(Tools.class.getClassLoader().getResource(path));
}

Surely there is a way to speed things up? I'm running this on a perfectly good Intel i5, it shouldn't be this slow, so it must be my code.


回答1:


Loading 113 images of a total of 159.14mb with...

public static void loadWithoutThreads(File[] array) {
    for (File file : array) {
        try {
            ImageIO.read(file);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

Took ~15s

With...

public static void loadWithThreads(File[] array) {

    final int threads = Runtime.getRuntime().availableProcessors();
    t = new Thread[threads];

    CountDownLatch latch = new CountDownLatch(threads);

    for (int i = 0; i < threads; i++) {
        t[i] = new Thread("HMediaConverter") {
            final int id = currentThreads;

            int items = (array.length / threads) * currentThreads;

            @Override
            public void run() {
                try {
                    System.out.println("Starting " + id);

                    for (int i = items; i < (items + (array.length / threads)); i++) {
                        try {
                            System.out.println(i + ": " + array[i]);
                            ImageIO.read(array[i]);
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                } finally {
                    latch.countDown();
                }

            }

        };
        t[i].setPriority(Thread.MAX_PRIORITY);
        System.out.println("Start " + i);
        t[i].start();
        currentThreads++;
    }

    try {
        latch.await();
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }
}

took ~11s

With...

public static void loadWithExecutor(File[] images) {
    ExecutorService service = Executors.newFixedThreadPool(2);
    List<ImageLoadingTask> tasks = new ArrayList<>(images.length);
    for (File file : images) {
        tasks.add(new ImageLoadingTask(file));
    }
    try {
        List<Future<BufferedImage>> results = service.invokeAll(tasks);
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }
    service.shutdown();
}

public static class ImageLoadingTask implements Callable<BufferedImage> {

    private File file;

    public ImageLoadingTask(File file) {
        this.file = file;
    }

    @Override
    public BufferedImage call() throws Exception {
        return ImageIO.read(file);
    }

}

Took ~7s

The ExecutorService is more efficient because when one thread is processing a larger file, the other can be processing a number of small files. This is achieved by pooling the threads that aren't doing any work until they are needed, allowing a thread to perform a lot of short work, while the other thread(s) are also busy. You don't need to wait as long

Have a look at Executors for more details




回答2:


The following is a re-write that should work that is close to what the op wrote. A re-write into A fixed-size thread pool would probably be better.

//import java.util.concurrent.atomic.AtomicInteger;

private static Thread[] t;

    private static AtomicInteger completedLoads = new AtomicInteger(0);

    public static void loadWithThreads(Object[] array, IntegerRunnable r) {

        final int threads =  Runtime.getRuntime().availableProcessors();
        t = new Thread[threads];
        completedLoads = new AtomicInteger(0);
        int targetLoads = array.length;
        int itemsPerThread = (array.length / threads);

        for (int i = 0; i < threads; i ++) {
            t[i] = new Thread("HMediaConverter" + i) {

                int startItem = itemsPerThread * i;

                @Override
                public void run() {

                    super.run();

                    for (int i = startItem; i < startItem + itemsPerThread; i ++) {
                        try {
                            r.run(i);
                         }
                         finally {
                                 completedLoads.incrementAndGet();
                         }
                    }
                }
            };
            t[i].setPriority(Thread.MAX_PRIORITY);
            t[i].start();
        }

        // Wait for the images to load    
        while (completedLoads.get() < targetLoads)
        {
                try {
                        Thread.sleep(100);
                }
                catch (InterruptedException ie) {
                        // ignore
                }
        }
    }



回答3:


Isolate which part does the slowing down - e.g by running System.currentTimeMillis() btween major segmnst then show us where is the biggest time - or show us all the program.

Threads handling as noted is questionable and you shouldn't use methods such as join etc out of the box unless you have seen it sometwhere provably working.

So post times and we'll take it from there - it could be the images it could be the threads



来源:https://stackoverflow.com/questions/34280566/java-multithreading-with-imageio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!