用与Java相同的方式使Clojure的println“线程安全”

glt*_*lts 1 concurrency multithreading clojure

println在Clojure中并发调用时,我发现它的行为与Java的行为不同System.out.println

我会用Java写什么

class Pcalls {
    public static void main(String[] args) {
        Runnable[] fns = new Runnable[3];
        for (int i = 0; i < 3; i++) {
            fns[i] = new Runnable() {
                @Override public void run() {
                    for (int i = 1; i <= 5; i++) {
                        System.out.println("Hello iteration " + i);
                    }
                }
            };
        }
        for (Runnable fn : fns) new Thread(fn).start();
    }
}
Run Code Online (Sandbox Code Playgroud)

我在Clojure中解释为:

(doall (apply pcalls
              (repeat 3 #(dotimes [i 5] (println "Hello iteration" (inc i))))))
Run Code Online (Sandbox Code Playgroud)

不幸的是,在Clojure版本中,输出行通常看起来是交错的:

Hello iterationHello iteration  1
Hello iteration Hello iteration 2
Hello iteration 3
1
Hello iteration 4
1
Hello iteration Hello iteration5
 Hello iteration 2
Hello iteration 23

Hello iteration Hello iteration 4
3Hello iteration 
5
Hello iteration 4
Hello iteration 5
(nil nil nil)
Run Code Online (Sandbox Code Playgroud)

在Java中,这永远不会发生,每条消息都打印在自己的行上。

您能否解释一下Clojure println与Java 的区别和原因,以及如何println在Clojure 中实现类似的“线程安全”行为?

noi*_*ith 5

clojure中的一个约定是lock *out*,它是指打印到的位置。

user> (doall (apply pcalls
            (repeat 3 #(dotimes [i 5]
                             (locking *out*
                               (println "Hello iteration" (inc i)))))))
Hello iteration 1
Hello iteration 1
Hello iteration 2
Hello iteration 3
Hello iteration 4
Hello iteration 5
Hello iteration 1
Hello iteration 2
Hello iteration 3
Hello iteration 4
Hello iteration 5
Hello iteration 2
Hello iteration 3
Hello iteration 4
Hello iteration 5
(nil nil nil)
Run Code Online (Sandbox Code Playgroud)