FileDescriptor.sync isn't using Blocker

Ron Pressler ron.pressler at oracle.com
Fri Jul 14 10:48:47 UTC 2023


The JEP attempts to use the term “pinning” precisely, although at other times we use it a bit more loosely.

Suppose you have a method readFromSocket() that does a blocking read from a socket. Ordinarily, this only blocks the virtual thread but not the OS thread. However, the thread can be in a state that we call “pinned” — e.g., if somewhere down the stack a monitor is held or a native method is in effect — in which case the same method will result in the OS thread blocking. The virtual thread’s VirtualThread.park method will attempt to suspend the thread’s continuation and fail because the thread is pinned. I.e. pinning means putting the thread in a state where attempting to suspending the continuation would fail.

Pinning in itself is not a problem. The issue is performing some blocking operation — which is also not a problem in itself — *while the thread is pinned*. If that happens very frequently and for long duration it may impact the application’s throughput.

*In addition to pinning*, some operations, such as filesystem operations, block the OS thread. Colloquially, we sometimes also call that pinning, but that is not the precise meaning, as in those situation VirtualThread.park isn’t called and there’s no attempt to suspend the continuation and unmount the virtual thread at all.

As to what users should avoid, that is a complicated question. It’s similar to asking what users should avoid to get good performance. It depends. As a rule of thumb, doing frequent and long-running blocking operations while a virtual thread is pinned could potentially be a performance issue, and in those situations synchronized blocks/methods should be replaced with j.u.c locks. As always, the more complete answer is that to get an application that performs well, users should profile it and use JFR, and let the profile tell them where the program’s hotspots and performance issues are. If blocking while pinned is a problem in a particular application, JFR should assist in diagnosing the problem.

So people should write simple blocking code, spawn lots and lots of virtual threads — a fresh one for every concurrent task in the application — and then, as they do for every application they want to perform well, they should profile. It is at that point that they should be aware of these issues and let JFR guide them as to whether pinning is a performance problem in their code.

— Ron

> On 14 Jul 2023, at 11:21, Cay Horstmann <cay.horstmann at gmail.com> wrote:
> 
> Il 14/07/2023 10.55, Alan Bateman ha scritto:
>> On 13/07/2023 20:23, Cay Horstmann wrote:
>>> 
>>> I re-read this a few times. Here is where I think there is confusion.
>>> 
>>> The first paragraph "The vast majority..." states: "However, some blocking operations in the JDK do not unmount the virtual thread, and thus block both its carrier and the underlying OS thread." It then goes on to say that the parallelism level expands.
>> This is paragraph 6, is is correct.
>>> 
>>> The following paragraph states: "There are two scenarios in which a virtual thread cannot be unmounted during blocking operations because it is pinned to its carrier:" In a subsequent paragraph: "The scheduler does not compensate for pinning by expanding its parallelism."
>> This paragraph is also correct it but I think what you are saying is that the discussion about expanding parallelism for OS operations that doesn't release the carrier is sticking in the reader's mind when they move onto the next paragraph about these two operations. We can look at this again to see if we can structure it better.
> 
> It's worse than that. I don't understand the order of exposition. First, there is a discussion of "some blocking operations in the JDK do not unmount the virtual thread", with two examples: "many filesystem operations" and Object.wait().
> 
> I understood "many filesystem operations" to mean operations such as FileInputStream.readBytes or FileOutputStream.writeBytes. Those are native methods. So the virtual thread is pinned.
> 
> Object.wait() can only be called when it owns the monitor of the object, so it must be inside a synchronized block or method, again pinned.
> 
> Assuming that I am understanding that right, maybe you should discuss pinning first?
> 
> Also, I would make it very clear what "pinning" is. Is the same as "unable to unmount"? Or is it your term specifically for the listed situations 1./2.?
> 
> Finally, in situation "1. When it executes code inside a synchronized block or method", what exactly is "inside". I assume that the thread is also pinned when blocking to acquire the monitor, which not everyone would consider to be "inside".
> 
> Cheers,
> 
> Cay
> 
> 
> -- 
> 
> --
> 
> Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com



More information about the loom-dev mailing list