Live data from Hacker News

We switched to Java 21 virtual threads and got a deadlock in TPC-C for Postgres

blog.ydb.tech

221–230 of 253 posts

Re: We switched to Java 21 virtual threads and got a deadlock in TPC-C for Postgres

#221

Earlier quoted context omitted.

> why waste bandwidth with images of four-handed people? In the end it's just 2x 40kb

So that makes a signal to noise ratio of 1:5 given the text including code is just 14kB.

For me the top 3 files downloaded by size are all js files that are about 450kb in total.

Also like 7 font files for ~100kb

Re: We switched to Java 21 virtual threads and got a deadlock in TPC-C for Postgres

#222
post #220

Earlier quoted context omitted.

I don't know man? We make scalable graphics rendering servers to stream things like videogames across the web. When we started the project to switch to virtual threads we had that as number one on the big board. "Rewrite for reentrant locks." Maybe we have more fastidious engineers than a normal company would since we are in the medical space? But even the juniors were reading and familiarizing themselves on how to p…

Wait, are you writing medical videogames?

We use the same technologies to deliver, say, remote CT review capability, that you would use to stream a videogame. It's just far more likely that the audience I'm communicating with, HN, is familiar with the requirements of videogame streaming, than it is that they are familiar with remote medical dataset viewing. Obviously the requirements or our use case are far more stringent, but no need to go into all that to illustrate the point made.

1 - Use virtual threads with reentrant locks if you need to do "true heavy" scaling.

2 - Kind of implied, but since you gave the opportunity to make it explicit with your comment =D, there is no need to waste your life on earning no money in videogames when the medical industry is right there willing to pay you 10x as much for the same skills. (Provided your skill is in the hard backend engine and physics work. They pay more for the ML too, if I'm being honest.)

Re: We switched to Java 21 virtual threads and got a deadlock in TPC-C for Postgres

#223

Earlier quoted context omitted.

NGINX is a native C implementation, so it has to be carefully written to use the OS's native high-performance IO and native OS threads. The purpose of project Loom is to abstract that away from Java application code. The runtime can use the most efficient IO for the given platform (ideally io_uring on Linux or IOCP on Windows, for example) even if the application code calls the old blocking File.Write(). The applicat…

Servicing 20,000 concurrent requests on a single box where somehow threads are the bottleneck, is that not a problem that approximately no one has?

Most application webservers (by default) handle one request per thread. For mostly IO bound stuff (which many projects are), it makes sense to me that threads become a bottleneck in relatively ordinary scenarios.

Re: We switched to Java 21 virtual threads and got a deadlock in TPC-C for Postgres

#224

I think i have a more elegant solution for this deadlock: "Switch to haskell".

If serious: that’s dismissive, superior, and a low-effort appeal to Haskell fans. If not serious: it’s still low effort, but while it is framed as a zinger, it’s not funny at all. I don’t even understand what the humor might be, maybe it’s serious after all.

It would have been better to write:

Switch to a language/runtime that's not only had virtual threads for decades, but also a saner synchronisation model (transactions) rather than synchronized blocks.

Re: We switched to Java 21 virtual threads and got a deadlock in TPC-C for Postgres

#225
post #136

I think i have a more elegant solution for this deadlock: "Switch to haskell".

Every language with sufficient concurrency and parallelism primitives are prone to dead locks/live locks and any other kind of race conditions.

Exactly! It's the same thing with memory management primitives. If you expose malloc and free directly to an application programmer, things will eventually get buggy.

It's better to hide the locking primitives and let the runtime handle it for you safely.

Re: We switched to Java 21 virtual threads and got a deadlock in TPC-C for Postgres

#226
post #39

Earlier quoted context omitted.

Is that all that's happening here? There's an implicit limit on real threads, where before it was unlimited by virtue of not using the virtual thread's limited pool? If it doesn't spawn threads when all of them are blocked, that seems kinda dumb. And a severe change in semantics. It can be conservative and try running unpinned ones on fewer threads and shuffle them around and slowly spawn more to ensure eventual prog…

The change in semantics is that while in principle your OS thread will always have a turn at making progress (assuming no super heavy spin locks etc), that isn't true for virtual threads. The classic situation and the one they hit in the article is something like this, You've got some virtual threads that encounter this code, synchronized(foo) { foo.wait() } And some other virtual threads that are in charge of awakin…

The only way I can see this being a problem is if the virtual threads can't be stolen from their (now pinned) carrier thread. Because otherwise that's all true of real threads too, blocking them is the whole point of Object.wait.

If there's no work-stealing from pinned carriers (or they're low-finite and normal threads are effectively infinite): yes that'd be a HUGE issue. I would be shocked if they released anything with that limitation though, that would violate some of the core expectations of mutexes and threads - independent ones need to make progress or nearly all patterns can't guarantee progress.

Re: We switched to Java 21 virtual threads and got a deadlock in TPC-C for Postgres

#227
post #109
post #91

Earlier quoted context omitted.

Shouldn't you be able to use the same number of real threads though, plus some additional effectively-threads for the virtual threads that are not pinned? Doesn't seem like this should change semantics there, so the risk would be code that changes because of perceived advantages which are not true in edge cases - that's new behavior that wasn't possible before, there aren't really any existing semantics to break. If…

That sort of what happens, there is just a configurable hard limit on how much new thread may be created that was hit by this benchmark. As mentioned in another comment: jdk.virtualThreadScheduler.maxPoolSize

Is there no limit (ignoring outside limits, e.g. from the OS) for normal threads? I know people usually use limited size thread pools for a variety of reasons, but I can't say that I've actually tried to exceed limits in a Java process yet...

That would indeed be a problem if it's not similarly unlimited by default. Configurable makes perfect sense, as does attempting to be conservative, but small hard-capped defaults are very obviously going to cause problems, especially while synchronized locks the carrier.

Re: We switched to Java 21 virtual threads and got a deadlock in TPC-C for Postgres

#228
I thought the blog was great but "in summary" conclusion bad.

The summary merely stated that Java virtual thread are great. I expected a summary of the problem and solution, for example something like:

When using Java 21 virtual threads, you can end-up starved of carrier threads due to all carrier threads waiting on a pool exhausted resources with no thread available to free such resources. The solution is to wrap those resources in a virtual-thread aware object. In our case, we solved our problem by wrapping connections in semaphores.

Re: We switched to Java 21 virtual threads and got a deadlock in TPC-C for Postgres

#229
post #128

Personally I am curious how these features like virtual threads are tested when developed.

The model has been extensively tested in TLA+, which can reason about all possible timing combinations, among other things.

Oh. Interesting. Never heard of it.

Re: We switched to Java 21 virtual threads and got a deadlock in TPC-C for Postgres

#230
post #205

Earlier quoted context omitted.

> have a good chance of using "synchronized" instead of other kinds of locks; and "synchronized" can be more robust than other kinds of locks (no risk of forgetting to release the lock, and on older JVMs, no risk of an out-of-memory while within the lock implementation breaking things), I haven't professionally written Java in years, however from what I remember synchronized was considered evil from day one. You can'…

Is there a similarly low-level synchronization mechanism that doesn't work this way? .NET's does the same thing. I guess I might have preferred if both Java and .NET had chosen to use a dedicated mutex object instead of hanging the whole thing off of just any old instance of Object. But that would have its own downsides, and the designers might have good reason to decide that they were worse. Not being able to just r…

In .net async won where lock and mutex does not work (lock is like synchronized, not exactly the same, tough). That’s why most libraries use SemaphoreSlim which would work with green threads. But that’s more because of the ecosystem. I’ve barley stumble upon lock’s and mutex is mostly used in the main method since it acquires a real os mutex, not really a cheap thing but for GUIs it’s clever to check if the app is running. Most libs that use system.threading.task use semaphoreslim tough.
Post reply on HN