3 ms·
> I agree with your point that tacking all of this onto the existing (flawed) Thread API is a risky move. This is not what Loom does, though. Virtual threads a
by pron 6y ago
> I agree with your point that tacking all of this onto the existing (flawed) Thread API is a risky move.
This is not what Loom does, though. Virtual threads are not using the thread API. They are (Java) threads; no more and no less than today's threads. Just as people don't normally use the java.lang.Thread API directly to use today's threads, there's no reason why they should use it with virtual threads.
> One advantage that colored functions do have is that you see it and "know" that the thing involves expensive and/or blocking work.
It gives you the illusion of knowing something that you don't really. The OS, or the Java runtime, can and do pause your thread at any point for durations that are between orders of magnitude shorter and orders of magnitude longer than some blocking operations. There is no useful semantic knowledge you can extract from knowing something is "blocking" to the point that it's a meaningless designation. It does mean something in "single-threaded" languages like JavaScript, or when programming hard realtime software, but not in ordinary Java. You're wasting a syntactic "colour" on zero bits of information.
- ragnese 6y ago> This is not what Loom does, though. Virtual threads are not using the thread API. They are (Java) threads; no more and no less than today's threads. Just as people don't normally use the java.lang.Thread API directly to use today's threads, there's no reason why they should use it with virtual threads. Right. That's fair. They are threads, but it's just that now you have two "kinds" of Thread, where before you had one (AFIAK). I like the analogy to "virtual memory" of an OS, but can applications ask for "real RAM" instead of "virtual RAM"? I don't think so, but I could be wrong. So having virtual threads and "raw" threads under the same class has pros and cons, IMO. > It gives you the illusion of knowing something that you don't really. The OS, or the Java runtime, can and do pause your thread at any point for durations that are between orders of magnitude shorter and orders of magnitude longer than blocking operations. There is no useful semantic knowledge you can extract from knowing something is "blocking" to the point that it's a meaningless designation. It does mean something in "single threaded" languages like JavaScript, but not in Java. That's true. But it's still a signal from the author of the function, the same way a type is. If a function makes a network call, you can be fairly sure that it will usually take longer to return than a function that is just flipping some bits around (even a fairly large amount of bits). Or do you still disagree? Would you say that if I'm writing JVM code, I really shouldn't worry about what functions make network and DB calls or what thread they're on because it really doesn't matter? Even if I have a UI that I'd like to keep responsive?
- pron 6y ago> So having virtual threads and "raw" threads under the same class has pros and cons, IMO. That's one way to think about it. Another is that Java never gives you "OS threads" it always gives you Java threads, an abstraction with multiple possible implementations. One implementation is no more real or raw than the other (in fact, you could even theoretically make virtual threads the carriers for other virtual threads -- a thread is a thread, after all -- but we explicitly blocked that because it's not useful). There is no real difference between that and ArrayList and LinkedList both implementing the same List interface. They're both just as real, but they have different footprint and performance (the class hierarchy for threads is slightly different, but for uninteresting technical reasons). > Or do you still disagree? I still disagree. That network call might take 1ms, and that bit fiddling might trigger a GC collection that takes 10 times that or more. Moreover, neither Kotlin nor C# mark long subroutines with a different colour, and they don't even mark blocking calls with a different colour, just the flavour of them that's to be used with coroutines. The real reason that colour is necessary is because of the way the feature is implemented. Originally, that colour meant to signify something else: nondeterminism in mostly-deterministic languages like Haskell, and it is also important in JavaScript. Trying to retroactively find a useful meaning for it in Java is an excuse.
- ragnese 6y agoFair point about the abstraction level of a Java thread vs an OS thread. In light of both things you just wrote, let me ask you this: why does Java give us any choice on thread implementation? Why not have everything be a green thread from now on? If Java threads are not OS threads, can be paused for any amount of time, and there's no reason that network calls or db calls or file IO should be treated any differently, then I'm not sure why the old Java Threads shouldn't be deprecated. Can you shine some light on that? After Loom drops, when would I ever want something other than a green thread?
- pron 6y agoThe first part of the answer is the same as that for a similar question we've been asked about LinkedList: we don't deprecate things that are heavily used, however useless or superseded by something else, unless they are very harmful. Deprecation in Java does not mean "unrecommended" but "absolutely do not use this if you want your program to continue working on future versions." Not only is it a compile-time warning, but JDK tooling even checks for uses of deprecated APIs in binaries and warns about them. Ideally, deprecated usages should break people's builds. In other words, deprecation is a big deal and not taken lightly. We might need another standardised term for "unrecommended" or "superseded". The second part of the answer is that there are still good uses cases for heavyweight threads, that are backed by one OS thread. For example, as carriers for virtual threads or parallel streams, i.e. as approximations of CPU cores, and also for cases where FFI is used for IO or some other native interaction. This is very rare in Java, but very rare could mean "used only in tens of thousands of programs rather than tens of millions".
- jillesvangurp 6y agoThey are threads in the same way that Java's original green threads were threads and in exactly the same way that co-routines are user scheduled thread like objects. They are not proper OS threads scheduled by the OS. Kotlin's co-routine implementation does something very similar and will just use a Loom thread when that becomes available. It will also use executors with multiple threads if you use the right dispatcher. I'm not sure I get your point about colored functions. Under the hood the compiler generates what is basically a callback structure not unlike what you get in javascript (i.e. a promise). It gains features like callback hierarchies, cancellation, etc. Loom fixes this by forcing you to wrap things with a Thread. Same kind of mental overhead.
- ragnese 6y ago> I'm not sure I get your point about colored functions. Under the hood the compiler generates what is basically a callback structure not unlike what you get in javascript (i.e. a promise). It gains features like callback hierarchies, cancellation, etc. Loom fixes this by forcing you to wrap things with a Thread. Same kind of mental overhead. The difference is that I'm not allowed to pull apart the callback structure that colored functions (in Kotlin) cause the compiler to make. Instead, I just have a colored function I have to work with. And it's incompatible (in one direction) with functions of the wrong color. Colored functions don't compose well. The green thread approach allows you to call anything from anywhere and compose whatever you want. When you choose to make it asynchronous, then you wrap it in a green thread and fire it off. That's pretty different than having two juggle different colored functions AND still needing to fire them off via whatever coroutine laucher.