A sentinel value is a distinguished value whose agreed meaning signals a condition such as termination or absent input. Producers and consumers can pass it alongside ordinary business data, then recognize it by identity rather than ordinary equality. section 6.5
Stopping a waiting consumer
A producer-consumer pair can share a unique object as SENTINEL. The consumer processes queued objects, prints each hash, and exits when (identical? SENTINEL e) becomes true; later values are not processed. section 6.5
(import 'java.util.concurrent.LinkedBlockingQueue)
(def channel (LinkedBlockingQueue. 1)) ; #1
(def SENTINEL (Object.)) ; #2
(defn encode [] ; #3
(let [e (.take channel)]
(if (identical? SENTINEL e)
(println "done")
(do (println (hash e))
(recur)))))
(defn start [] ; #4
(let [out *out*]
(.start (Thread.
#(binding [*out* out]
(encode))))))
(do
(start)
(.offer channel :a)
(.offer channel (Object.)) ; #5
(.offer channel SENTINEL)
(.offer channel :a)) ; #6
;; -2123407586
;; 1430420663
;; done
Inspect the complete Clojure example using LinkedBlockingQueue, a worker thread, ordinary events, and a shared sentinel object. section 6.5

