Hacker News new | ask | show | jobs
by horizion2025 340 days ago
Java's new philosophy (in "Loom" - in production OpenJDK now) seems to be virtual threads that are cheap and can therefore be plentiful compared to native threads. This allows you to write the code in the old way without programmer-visible async.
2 comments

That sounds interesting, I'll take a look! (although not using native threads is almost never about perf)
Ok, but virtual threads still need thread synchronization.
which isn't a problem unless you are abusing threads.

If you avoid synchronization, like javascript then you also don't get pre-emption or parallelism.

> which isn't a problem unless you are abusing threads.

Well, some people would call this a problem (or downside). Many real-world programs need to access shared state or exchange data between client. This is significantly less error prone if everything happens on a single thread.

> If you avoid synchronization, like javascript then you also don't get pre-emption or parallelism.

When we are talking about networking, most of the time is spent waiting for I/O. We need concurrency, but there's typically no need for actual CPU level parallelism.

I'm not saying that we shouldn't use threads at all - on the contrary! -, but we should use them where they make sense. In some cases we can't even avoid it (e.g. audio).

A typical modern desktop application, for example, would have the UI on the main thread, all the networking on a network thread, audio on an audio thread, expensive calculations on a worker thread (pool), etc.

IMO it just doesn't make sense to complicate things by having one thread per socket when all the networking can easily be served by a single thread.

> having one thread per socket

I didn’t say that. You can serve multiple sockets on a thread.

I could respond to more points. But ultimately my point is that if, for, switch etc is the kind of code you can read and debug. And async/callback is not. Async await tries to make the code look more like regular code but doesn’t succeed. I’m just advocating for actually writing normal blocking code.

A thread is exactly the right abstraction - a program flow. Synchronization is a reality of having multiple flows of execution.

I’m interested in the project mentioned in the sibling comment about virtual threads which maybe reduces the overhead (alleviating your I/O bound concern) but allows you to write this normal code.

> You can serve multiple sockets on a thread.

But how would you do that with blocking I/O (which you have been suggesting)? As soon as multiple sockets are receiving data, blocking I/O requires threads.

> Async await tries to make the code look more like regular code but doesn’t succeed.

Can you be more specific? I'm personally very happy with ASIO + coroutines.

> A thread is exactly the right abstraction - a program flow.

IMO the right abstraction for concurrent program flow are suspendable and resumable functions (= coroutines) because you know exactly how the individual subprograms may interleave.

OS threads add parallelism, which means the subprograms can interleave at arbitrary points. This actually takes away control from you, which you then have to regain with critical sections, message queues, etc.

> Synchronization is a reality of having multiple flows of execution.

Depends on what kind of synchronization you're talking about. Thread synchronization is obviously only required when you have more than one thread.

> But how would you do that with blocking I/O

when you read/write to a socket you can configure a timeout with the kernel to wait. If no data is ready, you can try another socket. The timeout can be 0

So you can serve N sockets in a while loop by checking one at a time which is ready.

> Can you be more specific? I'm personally very happy with ASIO + coroutines

1. You now have to color every function as async and there is an arbitrary boundary between them.

2. The debugger doesn’t work.

3. Because there is no pre-emption long tasks can starve others.

4. When designing an API you have to consider whether to use coroutines or not and either approach is incompatible with the other.

> Thread synchronization is obviously only required when you have more than one thread.

Higher level concept. if you have two running independent computations they must synchronize. Or they aren’t really independent (what you’re praising).