Java - 使用ImageIO进行多线程处理

时间:2015-12-15 03:19:58

标签: java multithreading javax.imageio

我有一个加载缓慢的程序,我想这是由于我必须在开始时加载的图像资源量。我认为多线程会有所帮助,但现在我不太确定。这是我的自动多线程方法。

magic.mgc

这是我的图片加载代码:

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

当然有办法加快速度吗?我在非常好的Intel i5上运行它,它不应该这么慢,所以它必须是我的代码。

3 个答案:

答案 0 :(得分:3)

使用...

加载113张共159.14mb的图像
public static void loadWithoutThreads(File[] array) {
    for (File file : array) {
        try {
            ImageIO.read(file);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

花了~15s

使用...

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();
    }
}

花了~11s

随着......

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

}

花了~7s

ExecutorService效率更高,因为当一个线程正在处理更大的文件时,另一个线程可以处理许多小文件。这是通过汇集在需要之前不做任何工作的线程来实现的,允许线程执行大量的短工作,而其他线程也很忙。你不需要等待很长时间

有关详细信息,请查看Executors

答案 1 :(得分:1)

以下是重写,应该与op所写的一致。重写到固定大小的线程池可能会更好。

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

答案 2 :(得分:0)

隔离哪个部分放慢速度 - 例如在主要的segmnst之间运行System.currentTimeMillis()然后告诉我们最大的时间在哪里 - 或者向我们展示所有的程序。

如上所述,线程处理是有问题的,你不应该使用诸如加入等开箱即用的方法,除非你已经看到它可以在某处工作。

所以发布时间我们会从那里拿走它 - 它可能是它可能是线程的图像