I like how C# handles this. You're not forced to support cancellation, but it's strongly encouraged. The APIs all take a CancellationToken, which is driven by a CancellationTokenSource from the ultimate caller. This can then either be manually checked, or when you call a library API it will notice and throw an OperationCancelledException.
Edit: note that there is a "wrong" way to do this as well. The Java thread library provides a stop() function. But since that's exogenous, it doesn't necessarily get cleaned up properly. We had to have an effort to purge it from our codebase after discovering that stopping a thread while GRPC was in progress broke all future GRPC calls from all threads, presumably due to some shared data structure being left inconsistent. "Cooperative" (as opposed to preemptive) cancel is much cleaner.
I am surprised that you had to go out of your way to remove Thread.stop from existing Java code. It's been deprecated since 1998, and the javadoc page explains pretty clearly why it's inherently unsafe.
It's hard to miss all the warnings unless you're literally just looking at the method name and nothing else.
Not to mention that I feel like it's pretty unusual to be creating and managing threads yourself in Java these days, instead of using a thread pool/executor.
That’s barely-junior interview question indeed.
I was certainly surprised to see it when I found it.
One of Java's the ecosystem fundamental platforms is that it's multi-threading. It's gone through too many models.
And since Java has a metric ton of blog posts from the 2000s and 2010s, a lot of search engines lead you to older models.java itself has gone from green threads to OS threads and back to green threads now.
AbortSignal is same thing on the Web. It's unfortunate TC39 failed to ever bring a CancelToken to the language to standardize the pattern outside browsers.
Browsers have said that they are unwilling to ship any new cancelation mechanisms given that AbortSignal already exists, so we can't ship a different CancelToken. But I think there's a path to standardizing a subset of the existing AbortSignal machinery [1].
(I am on TC39 and while this isn't my highest priority I did bring the topic for discussion at the last meeting [2], and there was support from the rest of committee.)
[1] https://github.com/tc39/proposal-concurrency-control/issues/...
TC39 seems to be failing at many things for the past 10 years.
Hard disagree, TC39 has done great work over the last 10 years. To name a few: - Async/await - Rest/spread - Async iterators - WeakRefs - Explicit Resource Management - Temporal
It's decisions are much more well thought out than WHATWG standards. AbortSignal extending from EventTarget was a terrible call.
many things !== all the things
More good works from the last 10 years includes .at(), nullish chaining, BigInt etc.
But most of what you mentioned is closing in on 10 years in the standard (Async/Await is from 2017) meaning the bulk of the work done is from over 10 years ago.
The failure of AbortSignal is exactly the kind of failure TC39 has been doing in bulk lately. I have been following the proposal to add Observables to the language, which is a stage 1 proposal (and has been for over 10 years!!!). There were talks 5 years ago (!) to align the API with AbortSignal[1] which I think really exemplifies the inability for TC39 to reach a workable decision (at least as it operates now).
Another example I like to bring up are the failure of the pipeline operator[2], which was advanced to stage-2 four years ago and has been in hiatus ever since with very little work to show for it. After years of deliberation very controversal version of the operator with a massive community backlash. Before they advanced it it was one of the more popular proposals, now, not so much, and personally I sense any enthusiasm for this feature has pretty much vanished. In other words I think they took half a decade to make the obviously wrong decision, and have since given up.
From the failure of the pipeline operator followed a bunch of half-measures such as array grouping, and iterator helpers etc. which could have easily been implemented in userland libraries if the more functional version of the pipeline operator would have advanced.
I don't like it - you're forced to pass around this token, constantly manage the lifecycle of cancellation sources - and incredibly bug prone thing in async context, and it quickly gets very confusing when you have multiple tokens/sources.
I understand why they did it - a promise essentially is just some code, and a callback that will be triggered by someone at some point in time - you obviously get no quality of service promises on what happens if you cancel a promise, unless you as a dev take care to offer some.
It's also obvious that some operations are not necessarily designed to be cancellable - imagine a 'delete user' request - you cancelled it, now do you still have a user? Maybe, maybe you have some cruft lying around.
But still, other than the obvious wrong solution - C# had a Thread.Abort() similar to the stop() function that you mentioned, that was basically excommunicated from .NET more then a decade ago, I'm still not happy with the right one.
Very rare unless you are spawning your own.> ...constantly manage the lifecycle of cancellation sourcesUsually, you are passing through a runtime provided token (e.g. ASP.NET).
Not that rare in my experience, I constantly had to write software like this. Not every day, but it certainly did come up quite often in my code and others'
Oh and oone more thing - the very (developer-managed) complexity makes it that people constantly got it wrong, usually just enough (as often with the case of threading) that it worked fine 90% of the time, and was very hard to make a case to management why we should invest effort into fixing it.
C# has very good support for this.
You can even link cancellation tokens together and have different cancellation "roots".
> "Cooperative" (as opposed to preemptive) cancel is much cleaner.
Which what Thread.interrupt does.