2015-12-15 36 views
1

我有一個加載速度很慢的程序,我想這是由於我必須在開始時加載的圖像資源數量所致。我認爲多線程會有所幫助,但現在我不太確定。這是我的自動多線程方法。Java - 使用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)); 
} 

肯定有一種方法可以加快速度?我在一個完美的英特爾i5上運行這個,它不應該這麼慢,所以它一定是我的代碼。

+2

使用'ExecutorService'相反,可能不會解決問題,但它是你正在做什麼,然後有很多清潔現在 – MadProgrammer

+1

另外,一旦'Thread'的'run'方法存在,它就不能重新啓動 – MadProgrammer

+0

@MadProgrammer當我說'run()'方法不可能的時候,我可以問你指的是什麼嗎?重新啓動?我不太明白你在做什麼。並感謝您的快速反饋;我很感激。 – PragmaticObject

回答

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更多細節

0

隔離哪個部分會減慢速度 - 例如通過運行System.currentTimeMillis(),然後向我們展示最大時間在哪裏 - 或向我們展示所有程序。

如前所述的線程處理是有問題的,你不應該使用諸如join等開箱即用的方法,除非你已經看到它在某種程度上可行的工作。

所以發佈時間,我們就會把它從那裏 - 它可能是圖像也可能是線程

+0

聽起來不錯,不過我會說,加入這種線程可以將速度提高几百毫秒,但不會達到我想要的水平。 – PragmaticObject

1

以下是重新寫,應該工作接近於運算寫什麼。重新寫入固定大小的線程池可能會更好。

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

對'CountDownLatch'做一些快速的研究,你的'while(completedLoads.get() MadProgrammer