[英]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.