2015-04-03 103 views
4

我有一個ScheduledThreadPoolExecutor與4個活動線程。它充滿了大量的任務,每個任務處理一大堆項目。使用一個Java 8 Consumer作爲Runnable回調 - 是線程安全的嗎?

每個任務必須有3個回調:每個處理的項目後有開始,結束和一個回調。

每個回調都會在我的數據庫中觸發更新。這是一個有點長時間運行的任務。


下面是一段示例代碼,這應該說明我在做什麼:

public static void main(String[] args) throws InterruptedException { 
    ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(4); 

    Consumer<String> processed = (String o) -> { 
      System.err.println("PROCESSED: " + o); 
      try { Thread.sleep(10); } 
      catch (Exception e) { e.printStackTrace(); } 
    }; 

    for(int i=0; i<10; i++) { 
     executor.schedule(
       new ChunkTask("task"+i, processed), 
       500, 
       TimeUnit.MILLISECONDS 
     ); 
    } 

} 


public static class ChunkTask implements Runnable { 
    String taskId; 
    Consumer<String> processedCallback; 

    public ChunkTask(String taskId, Consumer<String> processedCallback) { 
     this.taskId = taskId; 
     this.processedCallback = processedCallback; 
    } 

    @Override 
    public void run() { 
     for(int i=0; i<50; i++) { 
      processedCallback.accept(taskId+" "+i); 
     } 
    } 
} 

我只是省略了開始和結束回調,因爲它基本上是一樣的處理回調。


正如您所看到的,我創建了一個Consumer對象。其中有一個Thread.sleep(10)來模擬數據庫訪問。這個對象被所有4個線程並行調用。

我不知道這是否是線程安全的。 在我看來,Consumer只是一個無狀態的對象,具有無狀態的方法。儘管可以多次並行調用它。

我對不對?


編輯:我知道我的回調是同步的。這只是爲了測試。後來我想讓它成爲異步。

+0

線程安全是一個複雜的問題。建議您閱讀_Java併發實踐_... – 2015-04-03 19:09:03

回答

2

是的,你的消費者沒有任何狀態,所以它是線程安全的。它使用的唯一共享對象是System.err,它本身是線程安全的。

當然,在真實的代碼中,線程安全將取決於您所做的而不是打印到System.err。如果您使用共享數據庫服務並且此服務不是線程安全的,那麼您將遇到問題。

+0

謝謝。當然,數據庫訪問是線程安全的。最後一個問題是:我想在回調中安排新的線程。那安全嗎? – 2015-04-03 09:48:53

+1

AFAIK,是的。執行者是線程安全的。 – 2015-04-03 10:00:27

相關問題