簡體   English   中英

Java:使用 ExecutorService 進行並發

[英]Java: Using ExecutorService for concurrency

我想並行執行一些任務,所以我在 Java 中搜索多線程,我找到了這個類,ExecutorService。 我嘗試了一個簡單的例子,但我不確定它是否並行運行。

long startTime = System.currentTimeMillis();
List<Callable<String>> callables = new ArrayList<Callable<String>>();
ExecutorService executor = Executors.newCachedThreadPool();
callables.add(new Callable<String>() {
        public String call() {
            for (int i=0; i<100000; i++) {
                System.out.println("i "+i);
            }
            return "Task 1";
        }
    }
);
        
callables.add(new Callable<String>() {
        public String call() {
            for (int j=0; j<100000; j++) {
                System.out.println("j "+j);
            }
            return "Task 2";
        }
    }
);
        
callables.add(new Callable<String>() {
     public String call() {
          for (int k=0; k<100000; k++) {
              System.out.println("k "+k);
          } 
          return "Task 3";
      }
  }
);
try {
    List<Future<String>> futureLst = executor.invokeAll(callables);
    for (Future future : futureLst) {
        try {
            System.out.println(future.get());
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
executor.shutdown();
System.out.println("Time Taken - "+ (System.currentTimeMillis() - startTime));

上面的代碼按預期工作正常並打印計數並返回字符串。 上述程序執行所需的時間為“3229”毫秒。

我把上面的程序改寫如下,

long startTime = System.currentTimeMillis();
for (int i=0; i<100000; i++) {
    System.out.println("i "+i);
}
for (int j=0; j<100000; j++) {
    System.out.println("j "+j);
}
for (int k=0; k<100000; k++) {
    System.out.println("k "+k);
}
System.out.println("Time Taken - "+ (System.currentTimeMillis() - startTime));

這個程序花費的時間是“3104”毫秒,比並行執行編碼的時間少。

那么我在第一個程序中做錯了什么嗎? 我的第一個程序是否並行運行任務,因為我看到沒有線程花費的時間更少?

第一個是順序的,第二個是並行的——這很好。

看起來運行時間主要由System.out.println調用中緩慢的控制台寫入操作組成(請參閱為什么 System.out.println 這么慢? )。

如果您改為寫入文件,您應該觀察不同的行為(和並行版本加速)。

您的任務主要是使用System.out.println調用(即PrintStream.println方法)寫入標准輸出。 它最終調用PrintStream.write方法,其中主體已同步。 因此,您只是將時間浪費在創建線程和同步開銷上。 由於PrintStream本質上是順序的,它不能並行輸出,所以當單個流正在寫入時,其他人只是在等待它。 某些操作可以像 for 循環和字符串和數字的連接一樣並行化,但它們比輸出到 stdout 快得多。

為了從並發中獲得額外的性能,您應該避免使用共享的順序資源。 在您的情況下,它是標准輸出流。

你的代碼是正確的。 結果是由於計算太簡單,運行速度太快。 大部分運行時間由控制台輸出的速度決定,因此多線程的好處並不能彌補設置和關閉線程池的開銷。 此外,try-catch 設置還增加了一個小的開銷(非常小,但足以在這個簡單的場景中糾結結果)。 --> 您可以嘗試增加循環大小(提示:使用靜態變量 MAX_LOOP 進行更快的測試),您將看到不同之處。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM