Java - Multithreading with ImageIO

给你一囗甜甜゛ 提交于 2019-12-07 06:10:31

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

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
                }
        }
    }

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

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