Java - 多线程与 ImageIO [英] Java - Multithreading with ImageIO
问题描述
我有一个加载缓慢的程序,我想这是由于我在开始时必须加载的图像资源量.我认为多线程会有所帮助,但现在我不太确定.这是我的自动多线程方法.
私有静态线程[] t;私有静态 int currentThreads;public static void loadWithThreads(Object[] array, IntegerRunnable r) {final int 线程 = Runtime.getRuntime().availableProcessors();t = 新线程[线程];for (int i = 0; i < 线程; i ++) {t[i] = 新线程(HMediaConverter"){最终 int id = currentThreads;int items = (array.length/threads) * currentThreads;@覆盖公共无效运行(){超级运行();for (int i = items; i < (items + (array.length/threads)); i ++) {r.run(i);}//回收这个线程,以便它可以再次使用.尝试 {t[id].join();lock.notifyAll();当前线程 --;} catch (InterruptedException e) {e.printStackTrace();}}};t[i].setPriority(Thread.MAX_PRIORITY);t[i].start();当前线程++;}}
这是我的图片加载代码:
public static ImageIcon loadImageIcon(String path) {return new ImageIcon(ImageIO.read(Tools.class.getClassLoader().getResource(path));}
当然有办法加快速度吗?我在非常好的 Intel i5 上运行它,它不应该这么慢,所以它一定是我的代码.
Loading 113 图片共 159.14mb with...
public static void loadWithoutThreads(File[] array) {for(文件文件:数组){尝试 {ImageIO.read(文件);} catch (IOException ex) {ex.printStackTrace();}}}
花了大约 15 秒
随着...
public static void loadWithThreads(File[] array) {final int 线程 = Runtime.getRuntime().availableProcessors();t = 新线程[线程];CountDownLatch 锁存器 = new CountDownLatch(threads);for (int i = 0; i < 线程; i++) {t[i] = 新线程(HMediaConverter"){最终 int id = currentThreads;int items = (array.length/threads) * currentThreads;@覆盖公共无效运行(){尝试 {System.out.println("开始" + id);for (int i = items; i < (items + (array.length/threads)); i++) {尝试 {System.out.println(i + ": " + array[i]);ImageIO.read(array[i]);} catch (IOException ex) {ex.printStackTrace();}}} 最后 {闩锁.countDown();}}};t[i].setPriority(Thread.MAX_PRIORITY);System.out.println("开始" + i);t[i].start();当前线程++;}尝试 {闩锁.等待();} catch (InterruptedException ex) {ex.printStackTrace();}}
花了大约 11 秒
随着...
public static void loadWithExecutor(File[] images) {ExecutorService 服务 = Executors.newFixedThreadPool(2);列表任务 = 新的 ArrayList<>(images.length);对于(文件文件:图像){tasks.add(new ImageLoadingTask(file));}尝试 {列表<未来<缓冲图像>>结果 = service.invokeAll(tasks);} catch (InterruptedException ex) {ex.printStackTrace();}service.shutdown();}公共静态类 ImageLoadingTask 实现 Callable{私人档案档案;公共 ImageLoadingTask(文件文件){this.file = 文件;}@覆盖public BufferedImage call() 抛出异常 {返回 ImageIO.read(file);}}
花了~7s
ExecutorService
效率更高,因为当一个线程处理较大的文件时,另一个线程可以处理多个小文件.这是通过将在需要之前不做任何工作的线程进行池化来实现的,允许一个线程执行大量短期工作,而其他线程也很忙.你不需要等那么久
查看 Executors 了解更多详情>
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.
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
这篇关于Java - 多线程与 ImageIO的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!