"All concurrency issues boil down to coordinating access to mutable state. The less mutable state, the easier it is to ensure thread safety."
-- Java Concurrency in Practice (from Bill Clementson's blog)
Like Erlang, Clojure is becoming a very powerful concurrent oriented language. It is designed to be a simple language making it easier to coordinate access to resources.
"Agents provide independent, asynchronous change of individual locations. Agents are bound to a single storage location for their lifetime, and only allow mutation of that location (to a new state) to occur as a result of an action"
Here is a simple example of two agent functions 'agent' and 'send':
;; Simple example of agents (concurrent coding) in Clojure
;; The send function waits/hangs and then returns the result.
;; Note: only the calls to 'Thread.sleep' in the main program
;; block the main thread.
;; @see http://clojure.org/agents
;; Function definition: (agent <state>). Example, (agent "Init")
;; Function definition: (send <agent> <func> & <args>).
;; Example, (send abc (fn [_] "Done"))
;; (Author: Berlin Brown (on 1/5/2009))
;; (A) Define the agent as 'abc'.
(agent "Initial Value of Agent = This string"))
;; (B) The function to send a message to the agent.
(defn go 
;; Wait here for 5 seconds)
(. java.lang.Thread sleep 5000)
(println "Print from concurrent send agent")
"1 2 3 4 (Final Value, I am done)")))
;; (C) Main entry point of the program
(defn main 
;; (1) Send a message to 'abc' agent by calling 'go'
;; (2) Wait for 1 second
(. java.lang.Thread sleep 1000)
;; (3) What is the value, we shouldn't be done yet?
;; (4) Wait some more, 6 more seconds
(. java.lang.Thread sleep 6000)
;; (5) Hopefully after 7 seconds, the agent is done,
;; Check the value.
;; Wait a little bit more and then print done.
(. java.lang.Thread sleep 12000)
(. System exit 1)
;; End of Script
Output of Running Program
Initial Value of Agent
Print from send agent
1 2 3 4 (Final Value, I am done)
Clojure COP/OOP Article
Edited: Here is an example using a Java Thread approach (some code not included):
(defn file-monitor-loop [file]
(let [delay-t (prop-int resources-core-sys "Octane_Sys_filemonitor_delay")
enable-file-mon (prop-bool resources-win-opts "file_monitor_enabled")
pth (. file getAbsolutePath)]
(.start (new Thread (fn 
(while (not (. shell isDisposed))
(when (file-modified? file)
;; Reload the file as it grows and refresh
;; the file.
(open-file pth true)))))))))