1. 程式人生 > >多執行緒優化執行效率

多執行緒優化執行效率

在專案開發中,碰到了一些耗時任務的問題.

需要使用多執行緒,本文在使用原生JDK7的情況下優化

純非同步方式可以使用Java8或者引入RxJava框架進行程式設計。

普通任務

同步任務流程圖如下

同步任務

假定場景如下:

  • taskA 耗時1秒
  • taskB 耗時2秒
  • taskC 耗時3秒

通常的操作就是遍歷任務+執行任務, 程式碼如下

    // 任務A
    Runnable taskA = ()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
    // 任務B
        Runnable taskB = ()->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
    // 任務C
        Runnable taskC = ()->{
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
    // 任務組
        Runnable [] taskArray = new Runnable[]{taskA,taskB,taskC};
    
        /**
         * 執行所有人物
         */
        @Test
        public void testSimple(){
            Date start = new Date();
            for (Runnable aTaskArray : taskArray) {
                aTaskArray.run();
            }
            Date end = new Date();
            System.out.println(end.getTime()-start.getTime());
        }

完成任務耗時6

多執行緒同步任務

為了提高執行效率,引入多執行緒,讓等待的時間不再累計,而是合併。

最終執行的時間是耗時最長的任務執行時間

如下圖所示,多個任務同時執行

多執行緒同步任務

程式碼

為了簡便起見,使用了上面的任務組taskArray物件。

在實際使用中可以自己實現Runnable介面並傳入CountDownLatch物件進行操作

    /**
     * 同步等待所有任務處理完成方案
     */
    @Test
    public void testSync() throws InterruptedException {
        final CountDownLatch countDownLatch = new CountDownLatch(taskArray.length);
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        Date start = new Date();
        for (Runnable aTaskArray : taskArray) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    aTaskArray.run();
                    countDownLatch.countDown();
                }
            });

        }
        countDownLatch.await();
        Date end = new Date();
        System.out.println(end.getTime()-start.getTime());
    }

執行時間: 3

使用 JDK5 提供的 CountDownLatch 進行同步優化

優點

  • 不用修改後續的程式碼(因為是同步的,後續的內容依賴於本次的內容也不影響)

缺點

  • 會造成呼叫執行緒等待

多執行緒非同步任務

多執行緒非同步任務

     /**
        * 非同步回撥方案
        * @throws InterruptedException
        */
       @Test
       public void testReturnAsync() throws InterruptedException {
           ExecutorService executorService = Executors.newFixedThreadPool(3);
           Date start = new Date();
           AtomicInteger atomicInteger = new AtomicInteger(taskArray.length);
           for (Runnable aTaskArray : taskArray) {
   
               executorService.execute(new Runnable() {
                   @Override
                   public void run() {
                       aTaskArray.run();
                       if(atomicInteger.decrementAndGet()==0){
                           Date end = new Date();
                           System.out.println(end.getTime()-start.getTime());
                       }
                   }
               });
   
           }
           System.out.println("等待子執行緒的結果");
           Thread.sleep(5*1000);
       }

執行時間: 3

優點

  • 不會造成呼叫執行緒等待

缺點:

  • 需要修改了法簽名,需要傳入Runnable物件,執行回撥,後續的程式碼需要跟著修改

總結

  • 使用多執行緒非同步還是同步主要的決定因素在於:呼叫執行緒是不是可以阻塞
  • 多執行緒同步和多執行緒非同步的執行效率沒有差別