2016-03-01 15 views
0

我正在使用ExcutorService來提交併行運行的任務。任務的順序無關緊要。但是,服務可能會發生變化,特別是在請求的池的大小需要更改時。僅在單個入口點鎖定

public class Service { 

    private volatile ExecutorService service = Executors.newFixedThreadPool(4); 

    private final ReentrantLock serviceLock = new ReentrantLock(); 

    public Future<Object> postRequest(final Callable<Object> request) { 
     try { 
      serviceLock.lock(); // ? 
      return service.submit(request); 
     } finally { 
      serviceLock.unlock(); // ? 
     } 
    } 

    public void setSize(final int size) { 
     try { 
      if (size <= 0) { 
       throw new IllegalArgumentException("service pool size must positive"); 
      } 
      serviceLock.lock(); 

      service = Executors.newFixedThreadPool(size); 
     } finally { 
      serviceLock.unlock(); 
     } 
    } 
} 

很顯然,我不認爲我需要在postRequest方法的鎖定和解鎖,當它被調用的唯一方法。

我只需要在訪問setSize期間鎖定postRequest。否則,鎖定和解鎖所需的額外時間毫無意義。我認爲這是必要的,因爲與提交的數百個請求相比,大小很少會改變(可能是一次或兩次)。

有沒有辦法在不需要時(setSize未被訪問時)在postRequest上避免鎖定?

回答

0

由於執行程序實際上是一個ThreadPoolExecutor,因此您可以應用強制轉換並使用其setMaximumPoolSize方法。

如果將來更新JVM規範,您可以在setSize方法中添加一個類型檢查。

if (e instanceof ThreadPoolExecutor) { 
     ((ThreadPoolExecutor) e).setMaximumPoolSize(size); 
    } 

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html#setMaximumPoolSize(int)

+1

如果OP想要一個'ThreadPoolExecutor'的功能,那麼OP應該創建一個類型的變量,並明確創建該類型的對象。使用類型轉換或其他方式來顛覆庫函數的意圖是一種代碼異味。當有其他更簡單的方法來解決問題時,它的氣味更強烈。 –

+0

@james large:這是我的第一個答案。我稍後編輯了儘可能最小的修改代碼。可能不是我最好的想法... – Xvolks

0

@Obicere,你是對的,你不需要鎖定postRequest這將有性能開銷。 使用像這裏面postRequest

​​

另外,請考慮使用ThreadPoolExecutor代替FixedPoolThread因爲在你的情況,這是從來沒有一個固定的池線程:)

0

可以明確創建一個線程池執行人及然後使用setMaximumPoolSize():

private final ThreadPoolExecutor service = new ThreadPoolExecutor(4,4,0, TimeUnit.MINUTE, new LinkedBlockingQueue()); 


public void setSize(final int size) { 
service.setMaximumPoolSize(size); 
}