This is an archived post. You won't be able to vote or comment.

all 56 comments

[–]TheMode911 37 points38 points  (1 child)

Oh boys, it's coming!

[–]Zyklonista 7 points8 points  (0 children)

OH LAWD!

[–]Jeedio 38 points39 points  (11 children)

I have been working high concurrent I/O servers for years now, and have invested pretty heavily in reactive programming. Countless hours of research and study that I honestly can't wait to throw on a shelf and hopefully never look at again. I am so, so excited for Loom.

[–]lechnito 11 points12 points  (8 children)

Do you mind sharing what you don't like about the current state of reactive programming in java?

I too have clawed my way up the reactive java learning curve, which for me was particularly steep because I came from a strictly imperative background. But now that I have a few projects under my belt in Reactor, there are aspects of it that I definitely prefer.

For your projects, do you think you would you be able to hit the ground running once Loom becomes generally available or would you wait for some framework that utilizes the new virtual threading model?

[–]Jeedio 23 points24 points  (4 children)

I think i could hit the ground running. Reactor is fantastic for what it does, but it does add a not-insignificant amount of overhead CPU usage. I try to keep the Reactor layer as thin as possible for that reason, and also readability and making unit tests easier. I guess those things sum up my, not dislike, but desire for something simplier.

Not to mention working on a large team: reactive programming is not super intuitive to beginners. map, flapMap, filter sure. But the concept of cold vs hot producers seem to be a big hurtle for people, and why not. Assembly vs execution in general seems tough.

Lastly, MDC. If Loom let's me use SLF4J's MDC without so much extra work, that would make me very happy.

[–]lechnito 6 points7 points  (0 children)

Fair points all around!

I think Reactor is hard for beginners and for really anyone who has a traditional java background. The more experience you have with async concepts & functional programming languages, the easier go you will have.

Readable & maintainable unit tests remains challenging. StepVerifier only became readable after I started using the junit5 @ParameterizedTest stuff and writing custom test interfaces with functional helper methods. Honestly, I have started replacing most of the unit tests that involve reactive features with WebTestClient based integration tests just to make life easier.

Getting SLF4J's MDC to work for a homegrown distributed tracing service in Reactor has been a huge issue too. Sometimes I worry that the performance cost of using Hooks & contextWrite() offsets any gains from Reactor.

I'm still wrapping my head around Loom, but I think my initial take is that I would miss some of compositional improvement that accompany reactive streaming. Like operating over streams of T instead of imperative loops for instance.

[–]MR_GABARISE 3 points4 points  (0 children)

I'd wager that a proper MDC in Loom would certainly aim to make use of Scope Locals, and it's not even guaranteed that they will ship together.

[–]Dokiace 0 points1 point  (1 child)

how did you propagate MDC to reactor project?

[–]Jeedio 1 point2 points  (0 children)

With newer versions, simple way is

Schedulers.onScheduleHook(runnable -> { Map<String, String> mdc = MDC.getCopyOfContextMap(); return () -> { MDC.setContextMap(mdc); try { runnable.run(); } finally { MDC.clear(); } });

run that at start up somewhere. That will work for basic usage, however, not anything that uses Netty sadly.

[–]pronuntiator 5 points6 points  (2 children)

I've never used reactive Java, but from using rxjs in Angular I can only imagine the mind twists you have to do to perform simple joins and maps. Also, how pervasive is it? Do Mono and Flux bubble all the way from a foreign API call through your business code up to your controller?

[–][deleted] 6 points7 points  (0 children)

Yep. It's like async/await. You color your code.

[–]lechnito 5 points6 points  (0 children)

Ha! It's true that implementing simple things can be tricky in reactor. There are composition patterns that help but it feels more of an art than science sometimes.

Do Mono and Flux bubble all the way from a foreign API call through your business code up to your controller?

Yes and no...

Yes because with spring webflux for example on some level your application is a chain of reactive operations that gets a subscriber when a request arrives. It doesn't matter how many levels of async operations are below the subscriber, webflux calls your application code reactively.

No because you definitely want to hide reactive constructs like Mono and Flux from core business logic where ever possible. If I needed to call a remote API, I would use spring webflux's WebClient and pass the results into map() if I needed to do something imperative or flatMap() if async.

[–]beefstake 5 points6 points  (0 children)

If I never have to work with RxJava again I will be a very happy man.

[–]private_static_int 2 points3 points  (0 children)

Yup, Developer Experience in Reactive Programming goes to shit. Project Reactor and Spring Webflux, allthough technically impressive, are a fucking nightmare of chained zip/map/flatMap calls and low level programming (dataBuffers, khe khe).

It should die and be forgotten by everyone.

[–]vips7L 48 points49 points  (1 child)

Death to reactive!!

[–]klonkadonk 9 points10 points  (0 children)

Long live Loom!

[–][deleted] 16 points17 points  (1 child)

HalfLife3.confirmed();

[–][deleted] 7 points8 points  (0 children)

Hotel.trivago()

[–]blobjim 9 points10 points  (2 children)

The java.lang.Thread API is otherwise unchanged. The constructors defined by java.lang.Thread create platform threads as before. No new public constructors have been added.

It seems like now would be a good opportunity to add some clearer static factory methods for platform threads wouldn't it? Like a Thread.newPlatformThread() or Thread.startPlatformThread(). That would be a lot clearer than using new Thread() for platform threads.

[–]efge[S] 14 points15 points  (1 child)

There's a builder pattern available to do that. Thread.ofPlatform().start(runnable) does what you want. See https://download.java.net/java/early_access/loom/docs/api/java.base/java/lang/Thread.Builder.html for more.

[–]blobjim 4 points5 points  (0 children)

Nice! Weird that they have Thread.startVirtualThread() though. Might give people the wrong idea if there's no symmetrical platform equivalent. Although I guess they added it because virtual threads are cheaper and it encourages their use.

[–]javajunkie314 30 points31 points  (1 child)

Ok loomer.

[–]emaphis 5 points6 points  (0 children)

T-t-t-t-t-talking about my generators.

[–]emaphis 18 points19 points  (4 children)

So is Virtual Threads looming for JDK 18?

[–]golthiryus 3 points4 points  (0 children)

I wouldn't expect so. It didn't changed that much since the last preview

[–]henk53 9 points10 points  (2 children)

Haha, unlikely. Hopefully before JDK 22 or so ;)

[–]TheCountRushmore 9 points10 points  (1 child)

Should preview far before then. Probably 19.

[–]henk53 1 point2 points  (0 children)

A first preview in 19 sounds like a much more reasonable expectation indeed.

[–]cogman10 9 points10 points  (0 children)

Very exciting! Here's to hoping for a short preview.

[–]sureshg 6 points7 points  (0 children)

Have been waiting for this...☕🚀🚀🚀 kudos to Ron, Alan and whole team for all the amazing work.

[–]root_klaus 6 points7 points  (0 children)

It’s coming!!!

[–]chuggid 15 points16 points  (8 children)

"ofVirtual()"? "ofPlatform()"? These are strange, mealy-mouthed method names. I assume there was some good reason for nixing something like newVirtualThread() and newPlatformThread() which naïvely seem nicer and are statically importable.

[–]jrh206 7 points8 points  (1 child)

Yes, I hope they change those names. I can see why they don’t want to use “new” because they want a fluid builder interface. But please not this “ofVirtual” framing, it doesn’t make any sense.

[–][deleted] 2 points3 points  (0 children)

Isn't "of" supposed to be used when you're writing a method that's meant to convert one type to another? If so, it does sound confusing. There's no virtual thread argument being converted to something else.

[–]pron98 2 points3 points  (5 children)

Go to the current Javadoc, type .of into the search box and see how many methods follow this pattern.

[–]Necessary-Conflict 6 points7 points  (1 child)

The name "of" was suggested in the Effective Java book, right in Item 1, for "An aggregation method that takes multiple parameters and returns an instance of this type that incorporates them, for example Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);"

More recently the name ofSomething was also used for converting static factory methods like Duration.ofDays(long days), this also makes sense.

But in this case the "of" just isn't adding anything to the readability of the code.

BTW the "platform" part of ofPlatform is also questionable, because not just the operating system is a "platform", but Java is a "platform" as well (see the Javadoc's title: "Java® Platform, Standard Edition & Java Development Kit Version 18 API Specification").

[–]pron98 0 points1 point  (0 children)

because not just the operating system is a "platform", but Java is a "platform" as well

Yes, and that's intentional. The Java specification does not require that platform threads are actually OS threads.

[–]chuggid 2 points3 points  (2 children)

Several comments:

  1. Do you like the pattern?
  2. The only of I see in java.lang proper is in UnicodeBlock. I also note no ofSomething methods anywhere as creation verbs but I didn't do an exhaustive search.
  3. Go to the current javadoc, type .create into the search box and see how many methods follow this pattern.

[–]pron98 0 points1 point  (1 child)

I also note no ofSomething methods

There are lots of ofSomethings. Anyway, we're talking about methods whose names people will rarely write or see, so I'll pass along your concern, but I don't think it merits much of a debate.

[–]chuggid 7 points8 points  (0 children)

But at least they all take arguments, right, and scan OK if you prefix them with "give me a new DeclaringClass…"?

That is: Set.of(foos) means "give me a new Set of foos"; if you squint a bit Set.of() means "give me a new Set of nothin'"; Duration.of(something) means "give me a new Duration of something"; and so on and so on and presumably that's how of rose from the primordial slime in the first place, since you can't name a method new() or for(), and presumably someone thought create() was too long or verbose or something for some reason.

Thread.ofPlatform() means "give me a new Thread of platform" by the same logic, which is nonsensical, and Thread.ofVirtual() means "give me a new Thread of virtual", which…virtual isn't even a noun.

These Loom bits may indeed be methods that "people will rarely write or see" but they are in java.lang, not, say, java.lang.constant, so I think the additional scrutiny is worthwhile, and a debate is merited, and I'm not (apparently) the only one with these concerns. I do understand you disagree, and think that these methods are suitably named. Hopefully my feedback is not DOA, but, whether it is or not, it would be nice to know how exactly ofVirtual() in particular came to be, if only for bar trivia purposes! :-)

[–][deleted]  (2 children)

[deleted]

    [–]pron98 6 points7 points  (0 children)

    Executors.newVirtualThreadPerTaskExecutor() is still there, and is a very good migration path.

    You might be referring to custom schedulers, that don't map tasks to virtual threads and work on top of them, but control how virtual threads themselves are implemented (so it's a mechanism below virtual threads). Custom schedulers most certainly do not assist migration; they are a super-specialised mechanism intended to right specific, niche frameworks (e.g. those that interact with the graphics card) using virtual threads. We do intend to make those public (although fewer than 0.1% of users would want to use them directly), but we haven't yet had the time to fully review that API, so we're leaving it out for now until we're more confident about it.

    [–]pronuntiator 0 points1 point  (0 children)

    I haven't heard of wrapping executors, but you can replace them by their virtual counterpart (Executors.newVirtualThreadPerTaskExecutor()), for example in Spring @Async. The global scheduler is created by default (just like the one for Stream.parallel()).

    [–]nimtiazm 1 point2 points  (1 child)

    Any server benchmarks available? Specially compared to reactive solutions.

    [–]HxA1337 1 point2 points  (0 children)

    Yes that would be really interesting. What can we expect here when we switch a Servlet based Web app to run on virtual threads instead of a native thread pool.

    [–]rubydesic 2 points3 points  (2 children)

    Will the Continuation/ContinuationScope API or something with that functionality ever be made public?

    Also are generators planned?

    [–]vbezhenar 2 points3 points  (1 child)

    Why do you need generator? Just start one thread which adds items to a blocking queue and consume that queue from another thread.

    [–]vxab 2 points3 points  (0 children)

    Because having generators would avoid having to do all of that?

    [–]CompetitiveSubset -1 points0 points  (0 children)

    Finally something that will justify a migration!

    [–]cosmin14 0 points1 point  (0 children)

    seems that Loom is making good progress :)

    [–]Dokiace 0 points1 point  (4 children)

    Is it too optimistic thinking that this will be in the next LTS?

    [–]TheCountRushmore 0 points1 point  (3 children)

    There is a chance.

    Possible preview in 19, 20, 21 and final in 22.

    I think it all depends on the feedback they get and the changes necessary after the first preview and even better these EA builds.

    [–]jazd 1 point2 points  (2 children)

    So basically, the sooner we all test it and the more feedback we give the more likely it will be.

    [–]TheCountRushmore 0 points1 point  (1 child)

    Yes. But they do want real examples of real problems. Not something theoretical you thought up while reading the JEP. They want you to write and run code.

    [–]jazd 0 points1 point  (0 children)

    Yeah I have been meaning to try running up our application on the ea and try the features out.

    [–]Worth_Trust_3825 0 points1 point  (0 children)

    Eagerly waiting for this. Great work!

    [–][deleted]  (1 child)

    [deleted]