Java - 使用 ImageIO 的多线程
Java - Multithreading with ImageIO
我有一个加载缓慢的程序,我猜这是因为我一开始必须加载大量的图像资源。我认为多线程会有所帮助,但现在我不太确定。下面是我的自动多线程方法。
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 ++;
}
}
这是我的图片加载代码:
public static ImageIcon loadImageIcon(String path) {
return new ImageIcon(ImageIO.read(Tools.class.getClassLoader().getResource(path));
}
真的有办法加快速度吗?我 运行 这是在一个非常好的 Intel i5 上,它不应该这么慢,所以它一定是我的代码。
隔离哪个部分会减慢速度 - 例如通过 运行 System.currentTimeMillis() 在主要部分之间然后告诉我们最大时间在哪里 - 或者向我们展示所有程序。
所提到的线程处理是有问题的,你不应该使用开箱即用的方法,例如 join 等,除非你在某个地方看到它可以证明有效。
所以 post 次,我们将从那里获取它 - 它可能是图像,也可能是线程
以下是重写,应该可以接近操作员写的内容。重新写入固定大小的线程池可能会更好。
//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
}
}
}
正在加载总计 159.14mb 的 113 张图像...
public static void loadWithoutThreads(File[] array) {
for (File file : array) {
try {
ImageIO.read(file);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
用了 ~15 秒
有...
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();
}
}
用了 ~11 秒
与...
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);
}
}
用了 ~7 秒
ExecutorService
效率更高,因为当一个线程处理一个较大的文件时,另一个线程可以处理多个小文件。这是通过汇集那些在需要时不做任何工作的线程来实现的,允许一个线程执行大量短时间的工作,而其他线程也很忙。你不需要等那么久
查看 Executors 了解更多详情
我有一个加载缓慢的程序,我猜这是因为我一开始必须加载大量的图像资源。我认为多线程会有所帮助,但现在我不太确定。下面是我的自动多线程方法。
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 ++;
}
}
这是我的图片加载代码:
public static ImageIcon loadImageIcon(String path) {
return new ImageIcon(ImageIO.read(Tools.class.getClassLoader().getResource(path));
}
真的有办法加快速度吗?我 运行 这是在一个非常好的 Intel i5 上,它不应该这么慢,所以它一定是我的代码。
隔离哪个部分会减慢速度 - 例如通过 运行 System.currentTimeMillis() 在主要部分之间然后告诉我们最大时间在哪里 - 或者向我们展示所有程序。
所提到的线程处理是有问题的,你不应该使用开箱即用的方法,例如 join 等,除非你在某个地方看到它可以证明有效。
所以 post 次,我们将从那里获取它 - 它可能是图像,也可能是线程
以下是重写,应该可以接近操作员写的内容。重新写入固定大小的线程池可能会更好。
//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
}
}
}
正在加载总计 159.14mb 的 113 张图像...
public static void loadWithoutThreads(File[] array) {
for (File file : array) {
try {
ImageIO.read(file);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
用了 ~15 秒
有...
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();
}
}
用了 ~11 秒
与...
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);
}
}
用了 ~7 秒
ExecutorService
效率更高,因为当一个线程处理一个较大的文件时,另一个线程可以处理多个小文件。这是通过汇集那些在需要时不做任何工作的线程来实现的,允许一个线程执行大量短时间的工作,而其他线程也很忙。你不需要等那么久
查看 Executors 了解更多详情