single thread executor

Michael Bien mbien42 at gmail.com
Sun Sep 6 08:12:20 UTC 2020


it might help to think of it being two layers. You have plain old java 
threads which map to OS threads ("real" threads) and the new virtual 
threads.

Virtual threads can only make progress when they are mounted on carrier 
threads, which are "real" threads. They add a nice feature however: 
concurrent waiting (for resources) without blocking a carrier - which is 
a big deal.

to setup everything, carriers + virtuals:

|// plain old thread factory and thread pool using the new builder 
ThreadFactory carrierTF = Thread.builder().name("carrier#", 
0).factory(); ExecutorService carrierPool = 
Executors.newFixedThreadPool( CARRIER_THREAD_COUNT, carrierTF);|

|// factory for virtual threads scheduled on the carrier pool 
ThreadFactory virtualTF = Thread.builder() .virtual(carrierPool) 
.name("virtual#", 0).factory(); // thread executor will spawn a new 
virtual thread for each task |||ExecutorService |executor = Executors.newThreadExecutor(virtualTF);|



in a lot of cases you probably won't have to worry about carrier threads 
since it is already set up for you.
for example this will schedule a new virtual thread on the default 
scheduler, which is a ForkJoinPool.

|Thread.startVirtualThread(() -> { System.out.println("Hello Loom from 
"+Thread.currentThread()+"!"); });|


hope this helps a bit,

michael


- - -
mbien.dev

On 05.09.20 20:14, Miguel Ping wrote:
> Yeah I was about to reply exactly this.
>
> I always thought I knew basic executors, but now I find the api confusing:
> I create a ThreadExecutor that runs off a ThreadFactory (so far so good)
> that is built using virtual threads using a singleThreadExecutor.
> It's a bit confusing to see two executors here, but I guess the
> newThreadExecutor is just wrapping the threadFactory.
>
> Anyway, thanks alot for replying, especially on a saturday.
> I'm anxiously looking forward to continuing experimenting with Loom.
>
> Have a nice weekend.
>
> On Sat, Sep 5, 2020 at 6:02 PM Ron Pressler <ron.pressler at oracle.com> wrote:
>
>> Correction:
>>
>> It should be Executors.newThreadExecutor(tf) rather than
>> Executors.newUnboundedExecutor(tf).
>> The latter was the old API method, which has been renamed to the former.
>>
>> — Ron
>>
>>
>> On 4 September 2020 at 18:50:27, Ron Pressler (ron.pressler at oracle.com)
>> wrote:
>>
>> Remember, you want multiple virtual threads, but use only on platform
>> thread to schedule them. So you need to pass the single-thread executor
>> as the virtual thread scheduler:
>>
>>      ThreadFactory tf =
>> Thread.builder().virtual(Executors.newSingleThreadExecutor()).factory();
>>
>> And then you can use the thread factory directly to create virtual
>> threads,
>> or use it like so:
>>
>>      ExecutorService e = Executors.newUnboundedExecutor(tf);
>>
>> - Ron
>>
>>
>> On 4 September 2020 at 18:21:45, Miguel Ping (miguel.ping at gmail.com)
>> wrote:
>>
>> Hi all,
>>
>> I was experimenting with single thread executor and loom, and I was
>> expecting that if I have two tasks where the first call goes through
>> Socket.read, loom would schedule the second one. I'm pretty sure I'm doing
>> something wrong.
>>
>> Here's the output I got (I was expecting "Hello world" to appear before
>> "Connected!"; the program only concludes after I Ctrl+C the netcat
>> process):
>>
>>
>> $ nc -p 5555 -kl
>>
>> -- output --
>> sleeping 1s
>> Connected!
>> Hello world
>>
>> -- java --
>>
>> import java.net.InetSocketAddress;
>> import java.nio.ByteBuffer;
>> import java.nio.channels.SocketChannel;
>> import java.util.Arrays;
>> import java.util.concurrent.Callable;
>> import java.util.concurrent.Executors;
>>
>> public class Test {
>>
>> public static String block() {
>> // nc -p 5555 -kl
>> try {
>> System.out.println("sleeping 1s");
>> Thread.sleep(1000);
>> var socket = SocketChannel.open();
>> socket.connect(new InetSocketAddress("localhost", 5555));
>> System.out.println("Connected!");
>> socket.read(ByteBuffer.allocate(10)); // I was hoping this would allow the
>> other task to be scheduled
>> return "End";
>> } catch (Exception e) {
>> e.printStackTrace();
>> return "Failed";
>> }
>> }
>>
>> public static String print() {
>> System.out.println("Hello world");
>> return "Printed";
>> }
>>
>> public static void main(String[] args) throws Throwable {
>> var e = Executors.newFixedThreadPool(1,
>> Thread.builder().virtual().factory());
>> Callable<String> t1 = Test::block;
>> Callable<String> t2 = Test::print;
>>
>> var tasks = Arrays.asList(t1, t2);
>> var fut = e.invokeAll(tasks);
>> }
>> }
>>
>> --
>> Thanks
>>
>>



More information about the loom-dev mailing list