<div dir="ltr"><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">To elaborate a hit on why the single threaded task executor does not solve the concurrency problem. </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Imagine your tasks are “get account balance” and “set account balance” and these are available to external actors. You still need “lock account” and “unlock account” to make the system correct. </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Yes, you could instead write an atomic “get and update account” but this isn’t always possible. </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">The premise that making something single threaded removes concurrency issues is false. </blockquote><div><br></div><div><br></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div>That is true, we can not avoid locks, but locks implemented using plain variables with a mix of Thread.park/unpark are lighter than the same threads using classic locks. </div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div>And still, there is a perk of usage of complex data structures because of the cooperative nature of virtual thread scheduling.<br></div></blockquote></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jul 3, 2023 at 3:05 PM Robert Engels <<a href="mailto:rengels@ix.netcom.com">rengels@ix.netcom.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto"><div dir="ltr"></div><div dir="ltr">To elaborate a hit on why the single threaded task executor does not solve the concurrency problem. </div><div dir="ltr"><br></div><div dir="ltr">Imagine your tasks are “get account balance” and “set account balance” and these are available to external actors. You still need “lock account” and “unlock account” to make the system correct. </div><div dir="ltr"><br></div><div dir="ltr">Yes, you could instead write an atomic “get and update account” but this isn’t always possible. </div><div dir="ltr"><br></div><div dir="ltr">The premise that making something single threaded removes concurrency issues is false. </div><div dir="ltr"><br><blockquote type="cite">On Jul 3, 2023, at 7:51 AM, Robert Engels <<a href="mailto:rengels@ix.netcom.com" target="_blank">rengels@ix.netcom.com</a>> wrote:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><div dir="ltr"></div><div dir="ltr">That is an impossibility in Java. It is a shared memory system so you can not have guaranteed parallelism without concurrency concerns. If you guarantee to write your tasks in a concurrency safe way -you can already control the number of carrier threads. </div><div dir="ltr"><br></div><div dir="ltr">If is similar to Python - Python is single threaded (typically) but you can create multiple “threads” - and you still need to use locks to control access to shared data. </div><div dir="ltr"><br></div><div dir="ltr">Same with JavaScript (might be a better example). </div><div dir="ltr"><br><blockquote type="cite">On Jul 3, 2023, at 7:39 AM, Mushtaq Ahmed <<a href="mailto:mushtaq.a@gmail.com" target="_blank">mushtaq.a@gmail.com</a>> wrote:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><div dir="ltr"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">One important use case for me is being able to decompose code into a number of concurrent tasks, but without also having to deal with the complexity of parallelism-related data hazards.</blockquote><div><br></div><div>Thanks for articulating this so well. This is the exact use case we have. </div><div><br></div><div>I was very excited to read about the following API in early loom prototypes but it did not make it in the final release:</div><div><pre style="color:rgb(0,0,0)">Thread.builder().virtual(Executors.newSingleThreadExecutor()).factory()</pre><pre style="color:rgb(0,0,0)"><span style="color:rgb(34,34,34);font-family:Arial,Helvetica,sans-serif">Loom getting custom schedulers which allow this will be a big deal.</span></pre></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jul 3, 2023 at 4:15 PM Mark Raynsford <<a href="mailto:org.openjdk@io7m.com" target="_blank">org.openjdk@io7m.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 2023-07-02T21:15:29 +0000<br>
Ron Pressler <<a href="mailto:ron.pressler@oracle.com" target="_blank">ron.pressler@oracle.com</a>> wrote:<br>
><br>
> However, it’s important to remember that our priorities are primarily shaped by Java’s role as a *mainstream* platform and the demands of *mainstream* usages. In other words, what drives up the priority of the feature is not its hypothetical power but its potential use in mainstream applications because that’s where most of the value is, considering the majority of Java’s users. The more mainstream something is, the higher its priority. Given that custom schedulers address less mainstream uses than the default scheduler, they’re on the roadmap but not our highest priority at the moment.<br>
<br>
I feel obligated to bring this up every time the subject appears: One<br>
important use case for me is being able to decompose code into a number<br>
of concurrent tasks, but without also having to deal with the<br>
complexity of parallelism-related data hazards.<br>
<br>
In other words, I'd like to be able to use a set of virtual threads<br>
that are guaranteed to be scheduled on a single platform thread.<br>
This is a common approach used inside language interpreters embedded<br>
into game engines (typically Lua, although I hear C# is seeing use for<br>
this too nowadays).<br>
<br>
Game engines and simulations tend to comprise a large number of<br>
concurrent tasks, and much of the time those tasks need to access<br>
complex mutable state that is very difficult to reliably make<br>
thread-safe. Additionally, most of the time it's desirable for it<br>
to be possible to pause and resume the execution of individual tasks.<br>
<br>
Being able to map each task to a virtual thread, but have<br>
those virtual threads execute on a single platform thread would<br>
solve the problem in a very natural and pleasant way. Additionally,<br>
we'd get the ability to pause and resume a task without it losing its<br>
stack for free. Normally, that kind of thing has to be implemented<br>
manually.<br>
<br>
I agree it's definitely less mainstream. Most of the code I write isn't<br>
like this, but some of it is, and it desperately needs the mechanism<br>
that virtual threads don't quite provide yet. An early version did<br>
allow for specifying an executor service, but this was obviously taken<br>
out.<br>
<br>
-- <br>
Mark Raynsford | <a href="https://www.io7m.com" rel="noreferrer" target="_blank">https://www.io7m.com</a><br>
<br>
</blockquote></div></div>
</div></blockquote></div></blockquote></div></blockquote></div><br clear="all"><div><br></div><span class="gmail_signature_prefix">-- </span><br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><div dir="ltr">Best regards,<br>Andrii Lomakin.<br><br></div></div></div></div>