簡體   English   中英

在ExecutorService(Java / Clojure)內部休眠線程

[英]Sleeping a thread inside an ExecutorService (Java/Clojure)

我在clojure程序中創建了大量線程:

(import '(java.util.concurrent Executors)) 
(def *pool*   
  (Executors/newCachedThreadPool))

(defn do-something []
  ; work
  Thread/sleep 200
  ; repeat)

(dotimes [i 10000]
  (.submit *pool* do-something)) 

對我來說,在JVM之間已經有一段時間了,我基本上想知道在這里是否有任何反對在Executor執行的函數內部使用sleep或yield的論點? 如果我理解正確,在這種情況下,我的每個工人都有其自己的線程,因此應該沒有副作用。

如果執行程序使用的是FixedThreadPool:

(Executors/newFixedThreadPool 1000)

事情變得更加復雜,因為在完成工作之前線程不會返回到池中,這意味着如果線程正在睡眠,其他排隊的工作人員將需要更長的時間才能完成。

在這種情況下,我對線程的理解正確嗎?

(注意:我懷疑我的設計實際上是錯誤的,但是只是要確保我在正確的頁面上)

從概念上講,執行者是任務隊列+工作池。 您對此處將發生的情況的解釋基本上是正確的。 當您將任務提交給執行者時,工作被排隊,直到線程可以執行任務為止。 執行任務時,該任務擁有線程,休眠將阻止其他任務在該工作線程上執行。

取決於您正在執行的操作,這可能沒問題(盡管這是不尋常的,並且可能使任務中的睡眠形式變差)。 阻塞線程是等待IO的副作用(例如,阻塞在套接字或db調用上),這種情況更為常見。

通常,如果您要進行定期工作,最好在執行任務時在池外處理並激發任務,或者更好的是,使用Executors / newScheduledThreadPool中的ScheduledExecutorService代替。

Java中用於執行基於時間的任務的另一種主要機制是java.util.Timer ,該機制易於使用,但不如ScheduledExecutorService健壯。

Clojure的另一種替代方法是將工作程序顯式放入由Clojure而不是您管理的后台線程:

(defn do-task [] 
  (println (java.util.Date.) "doing task"))

(defn worker [f n wait]
            (doseq [task (repeat n f)]
                   (f)
                   (Thread/sleep wait)))

;; use future to execute worker in a background thread managed by Clojure
(future (worker do-task 10 1000))

;; the call to future returns immediately but in the background console
;; you will see the tasks being run.

休眠線程的一種替代方法是讓每個工作線程都有一個“ sleepUntil”長值。 當執行者呼叫工人時,如果工人正在睡覺,它將立即返回。 否則,它將執行其工作,然后返回。 這可以幫助您減少線程計數,因為FixedThreadPoolExecutor將能夠處理比其擁有的線程更多的工作線程,如果大多數線程被標記為睡眠並迅速返回。

暫無
暫無

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

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