You can use simulated threads with JavaPoly, which allows you to utilize the full Java threading model (including locks). If you enable the native jvm, you get true threads.
The reason you wouldn't want to use WebWorkers as a primitive for building threads is that the javascript memory model doesn't allow for shared memory, so you would take a huge performance hit while crossing the serialization boundary for virtually every memory access. You'd be better off just using the simulated threads at that point.