According to this discussion thread, Julia requires the number of kernel threads to be specified at startup: https://discourse.julialang.org/t/does-multithreading-requir... This seem to be more like pyprocessing and much more limited than the pthreads interface.
I didn't go deep on Julia's multithreading, but what he is saying is that Julia uses an MxN threading (I think nowadays if you don't specify it at startup it will just use one for each cpu thread), which is the same as a language I did most of distributed programming (elixir/erlang), and as far as I know it's the same as Go.
Having 1 kernel thread for each CPU thread means that your program can use all available CPU threads at the same time (so you get all the parallelism available within the machine), and having a language based scheduler for each thread means you can have minimal overhead (no need to do a system call) to create a new concurrent execution (meaning lightweight/green threading similar to what python allows, except being automatically distributed by the language within all kernel/cpu threads). In Elixir this means you can create millions of processes even though the OS will only see one thread per logical cpu thread, and I never felt the limitation of this abstraction over multiprocessing (of course, Julia is definitely nowhere near as mature - and maybe never will due to stuff like preemptive scheduling and parallel garbage collection that is easier to implement in a language with only immutable types, though it seems to be moving along, and in Julia 1.7 the processes being able to move between kernel threads solving the issue mentioned in that discussion you linked).
But that scheme is the same as green threading and has the same faults. Start Julia with one system thread. Run one infinite loop in one green thread and another in another green thread. One of the loops will run while the other will wait until the other completes (which it never does). This is inferior to Java and C# which both uses system threads by default, allowing both infinite loops to run. Erlang/Elixir has the same problem. You can run thousands of green threads, but if one of them is stupid enough to call a blocking C function then all others have to wait.
> Start Julia with one system thread. Run one infinite loop in one green thread and another in another green thread. One of the loops will run while the other will wait until the other completes (which it never does). This is inferior
If you want julia to use multiple system threads, why are you suggesting one not use system threads for this test? All you have to do is start julia with multiple threads and it'll use those threads for your infinite loops.
That issue actually doesn't happen with regular elixir, since it's immutable and stateless, the scheduler doesn't wait for the process to voluntarily wield (it's always safe to switch, so it just gives some fixed time for each process, which makes it very low latency and very reliable but not very efficient at any individual task due to all the switching). Calling other languages from erlang/elixir create dirty processes that can't be scheduled this way and may cause those issues.
Since I didn't use dirty processes in elixir it did make me forget about this obvious issue you pointed out, that for a mutable language like Julia can happen in every thread, but that's not something that limits the expressiveness of the model, but something that requires consideration to avoid while programming and language level mechanisms to protect the thread (at the very least the ability to define timeouts that can throw an exception on any spawned process) or maybe a future framework on top of it that handles this in a safer way (something like Akka). I can only hope Julia can achieve the full potential of it's multithreading model.