single thread executor

Ron Pressler ron.pressler at oracle.com
Sun Sep 6 10:26:36 UTC 2020


> in a lot of cases you probably won't have to worry about carrier threads
> since it is already set up for you.

Exactly! A custom virtual thread scheduler is an advanced feature that should 
only be used in special circumstances.

- Ron



On 6 September 2020 at 09:15:29, Michael Bien (mbien42 at gmail.com(mailto:mbien42 at gmail.com)) wrote:

> 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 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 t1 = Test::block;
> >> Callable t2 = Test::print;
> >>
> >> var tasks = Arrays.asList(t1, t2);
> >> var fut = e.invokeAll(tasks);
> >> }
> >> }
> >>
> >> --
> >> Thanks
> >>
> >>
>  



More information about the loom-dev mailing list