Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Untangled - Sneak Peek at Project Loom

Arnaud Bos
October 31, 2019

Untangled - Sneak Peek at Project Loom

Given at Voxxed Days Cluj 2019
Video: http://bit.ly/untangled-cluj-2019-video
Abstract:
Concurrent programming borrows a lot of terms from weaving and twists our minds with intertwined concepts: fibers, threads, lightweight-threads, green threads, loom...
Maybe you've heard about coroutines? Don't worry, everything is linked.

During this talk, we'll get weaving, show code samples and talk about project Loom, whose goal is to bring "lightweight concurrency" mechanisms to the JVM, along with APIs to embroider the story.

We will talk about project Loom's inception and recent prototypes. You will also see its mesh goes far beyond "simple" primitives to revolutionize the JVM.

Until then you will see how to follow that thread and become familiar with its concepts using the Quasar library.

Arnaud Bos

October 31, 2019
Tweet

More Decks by Arnaud Bos

Other Decks in Technology

Transcript

  1. private Connection.Available getConnection(long eta, long wait, String token) { for(;;)

    { if (eta > MAX_ETA_MS) { throw new EtaExceededException(); } if (wait > 0) { Thread.sleep(wait); } println("Retrying download after " + wait + "ms wait."); Connection c = coordinator.requestConnection(token); if (c instanceof Connection.Available) { return (Connection.Available) c; } Connection.Unavailable unavail = (Connection.Unavailable) c; eta = unavail.getEta(); wait = unavail.getWait(); token = unavail.getToken(); } }
  2. private Connection.Available getConnection(long eta, long wait, String token) { for(;;)

    { if (eta > MAX_ETA_MS) { throw new EtaExceededException(); } if (wait > 0) { Thread.sleep(wait); } println("Retrying download after " + wait + "ms wait."); Connection c = coordinator.requestConnection(token); if (c instanceof Connection.Available) { return (Connection.Available) c; } Connection.Unavailable unavail = (Connection.Unavailable) c; eta = unavail.getEta(); wait = unavail.getWait(); token = unavail.getToken(); } }
  3. private Connection.Available getConnection(long eta, long wait, String token) { for(;;)

    { if (eta > MAX_ETA_MS) { throw new EtaExceededException(); } if (wait > 0) { Thread.sleep(wait); } println("Retrying download after " + wait + "ms wait."); Connection c = coordinator.requestConnection(token); if (c instanceof Connection.Available) { return (Connection.Available) c; } Connection.Unavailable unavail = (Connection.Unavailable) c; eta = unavail.getEta(); wait = unavail.getWait(); token = unavail.getToken(); } }
  4. private Connection.Available getConnection(long eta, long wait, String token) { for(;;)

    { if (eta > MAX_ETA_MS) { throw new EtaExceededException(); } if (wait > 0) { Thread.sleep(wait); } println("Retrying download after " + wait + "ms wait."); Connection c = coordinator.requestConnection(token); if (c instanceof Connection.Available) { return (Connection.Available) c; } Connection.Unavailable unavail = (Connection.Unavailable) c; eta = unavail.getEta(); wait = unavail.getWait(); token = unavail.getToken(); } }
  5. private Connection.Available getConnection(long eta, long wait, String token) { for(;;)

    { if (eta > MAX_ETA_MS) { throw new EtaExceededException(); } if (wait > 0) { Thread.sleep(wait); } println("Retrying download after " + wait + "ms wait."); Connection c = coordinator.requestConnection(token); if (c instanceof Connection.Available) { return (Connection.Available) c; } Connection.Unavailable unavail = (Connection.Unavailable) c; eta = unavail.getEta(); wait = unavail.getWait(); token = unavail.getToken(); } }
  6. private Connection.Available getConnection(long eta, long wait, String token) { for(;;)

    { if (eta > MAX_ETA_MS) { throw new EtaExceededException(); } if (wait > 0) { Thread.sleep(wait); } println("Retrying download after " + wait + "ms wait."); Connection c = coordinator.requestConnection(token); if (c instanceof Connection.Available) { return (Connection.Available) c; } Connection.Unavailable unavail = (Connection.Unavailable) c; eta = unavail.getEta(); wait = unavail.getWait(); token = unavail.getToken(); } }
  7. private Connection.Available getConnection(long eta, long wait, String token) { for(;;)

    { if (eta > MAX_ETA_MS) { throw new EtaExceededException(); } if (wait > 0) { Thread.sleep(wait); } println("Retrying download after " + wait + "ms wait."); Connection c = coordinator.requestConnection(token); if (c instanceof Connection.Available) { return (Connection.Available) c; } Connection.Unavailable unavail = (Connection.Unavailable) c; eta = unavail.getEta(); wait = unavail.getWait(); token = unavail.getToken(); } }
  8. public static InputStream blockingRequest(String url, String headers) throws IOException {

    URL uri = new URL(url); SocketAddress serverAddress = new InetSocketAddress(uri.getHost(), uri.getPort() SocketChannel channel = SocketChannel.open(serverAddress); ByteBuffer buffer = ByteBuffer.wrap((headers + "Host: " + uri.getHost() + "\r\n\ do { channel.write(buffer); } while(buffer.hasRemaining()); return channel.socket().getInputStream(); }
  9. private void getConnection(long eta, long wait, String token, CompletionHandler<Connection.Available> handler)

    { if (eta > MAX_ETA_MS) { if (handler!=null) handler.failed(new EtaExceededException()); } boundedServiceExecutor.schedule(() -> { println("Retrying download after " + wait + "ms wait."); coordinator.requestConnection(token, new CompletionHandler<>() { @Override public void completed(Connection c) { if (c instanceof Connection.Available) { if (handler!=null) handler.completed((Connection.Available) c); } else { Connection.Unavailable unavail = (Connection.Unavailable) c; getConnection( unavail.getEta(), unavail.getWait(), unavail.getToken(), handler); } } @Override public void failed(Throwable t) { ...
  10. private void getConnection(long eta, long wait, String token, CompletionHandler<Connection.Available> handler)

    { if (eta > MAX_ETA_MS) { if (handler!=null) handler.failed(new EtaExceededException()); } boundedServiceExecutor.schedule(() -> { println("Retrying download after " + wait + "ms wait."); coordinator.requestConnection(token, new CompletionHandler<>() { @Override public void completed(Connection c) { if (c instanceof Connection.Available) { if (handler!=null) handler.completed((Connection.Available) c); } else { Connection.Unavailable unavail = (Connection.Unavailable) c; getConnection( unavail.getEta(), unavail.getWait(), unavail.getToken(), handler); } } @Override public void failed(Throwable t) { ...
  11. private void getConnection(long eta, long wait, String token, CompletionHandler<Connection.Available> handler)

    { if (eta > MAX_ETA_MS) { if (handler!=null) handler.failed(new EtaExceededException()); } boundedServiceExecutor.schedule(() -> { println("Retrying download after " + wait + "ms wait."); coordinator.requestConnection(token, new CompletionHandler<>() { @Override public void completed(Connection c) { if (c instanceof Connection.Available) { if (handler!=null) handler.completed((Connection.Available) c); } else { Connection.Unavailable unavail = (Connection.Unavailable) c; getConnection( unavail.getEta(), unavail.getWait(), unavail.getToken(), handler); } } @Override public void failed(Throwable t) { ...
  12. private void getConnection(long eta, long wait, String token, CompletionHandler<Connection.Available> handler)

    { if (eta > MAX_ETA_MS) { if (handler!=null) handler.failed(new EtaExceededException()); } boundedServiceExecutor.schedule(() -> { println("Retrying download after " + wait + "ms wait."); coordinator.requestConnection(token, new CompletionHandler<>() { @Override public void completed(Connection c) { if (c instanceof Connection.Available) { if (handler!=null) handler.completed((Connection.Available) c); } else { Connection.Unavailable unavail = (Connection.Unavailable) c; getConnection( unavail.getEta(), unavail.getWait(), unavail.getToken(), handler); } } @Override public void failed(Throwable t) { ...
  13. private void getConnection(long eta, long wait, String token, CompletionHandler<Connection.Available> handler)

    { if (eta > MAX_ETA_MS) { if (handler!=null) handler.failed(new EtaExceededException()); } boundedServiceExecutor.schedule(() -> { println("Retrying download after " + wait + "ms wait."); coordinator.requestConnection(token, new CompletionHandler<>() { @Override public void completed(Connection c) { if (c instanceof Connection.Available) { if (handler!=null) handler.completed((Connection.Available) c); } else { Connection.Unavailable unavail = (Connection.Unavailable) c; getConnection( unavail.getEta(), unavail.getWait(), unavail.getToken(), handler); } } @Override public void failed(Throwable t) { ...
  14. public static InputStream blockingRequest(String url, String headers) throws IOException {

    URL uri = new URL(url); SocketAddress serverAddress = new InetSocketAddress(uri.getHost(), uri.getPort() SocketChannel channel = SocketChannel.open(serverAddress); ByteBuffer buffer = ByteBuffer.wrap((headers + "Host: " + uri.getHost() + "\r\n\ do { channel.write(buffer); } while(buffer.hasRemaining()); return channel.socket().getInputStream(); }
  15. public static void asyncNonBlockingRequest(ExecutorService executor, String url, String headers, RequestHandler

    handler) { executor.submit(() -> { try { println("Starting request to " + url); URL uri = new URL(url); SocketAddress serverAddress = new InetSocketAddress(uri.getHost(), 80); AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(group); channel.connect(serverAddress, null, new CompletionHandler<Void>() { @Override public void completed(Void result, Void attachment) { ByteBuffer headersBuffer = ByteBuffer.wrap((headers + "Host: " + uri.getHost())); ByteBuffer responseBuffer = ByteBuffer.allocate(1024); channel.write(headersBuffer, headersBuffer, new CompletionHandler<>() { @Override public void completed(Integer written, ByteBuffer attachment) { if (attachment.hasRemaining()) { channel.write(attachment, attachment, this); } else { channel.read(responseBuffer, responseBuffer, new CompletionHandler<>() { @Override public void completed(Integer read, ByteBuffer attachment) { // More // this // way // ==>
  16. private Mono<Connection.Available> getConnection(long eta, long wait, String token) { AtomicLong

    etaRef = new AtomicLong(eta); AtomicLong waitRef = new AtomicLong(wait); AtomicReference<String> tokenRef = new AtomicReference<>(token); return Mono.defer(() -> { if (etaRef.get() > MAX_ETA_MS) { return Mono.error(new EtaExceededException()); } return Mono.delay(Duration.ofMillis(waitRef.get())) .flatMap(i -> coordinator.requestConnection(tokenRef.get())); }).flatMap(c -> { if (c instanceof Connection.Available) { return Mono.just((Connection.Available) c); } else { Connection.Unavailable unavail = (Connection.Unavailable) c; etaRef.set(unavail.getEta()); waitRef.set(unavail.getWait()); tokenRef.set(unavail.getToken()); return Mono.empty(); } }).repeatWhenEmpty(Repeat .onlyIf(ctx -> true) .doOnRepeat(ctx -> println(waitRef.get() + ", " + etaRef.get() + ", " + tokenRef.get()))); }
  17. private Mono<Connection.Available> getConnection(long eta, long wait, String token) { AtomicLong

    etaRef = new AtomicLong(eta); AtomicLong waitRef = new AtomicLong(wait); AtomicReference<String> tokenRef = new AtomicReference<>(token); return Mono.defer(() -> { if (etaRef.get() > MAX_ETA_MS) { return Mono.error(new EtaExceededException()); } return Mono.delay(Duration.ofMillis(waitRef.get())) .flatMap(i -> coordinator.requestConnection(tokenRef.get())); }).flatMap(c -> { if (c instanceof Connection.Available) { return Mono.just((Connection.Available) c); } else { Connection.Unavailable unavail = (Connection.Unavailable) c; etaRef.set(unavail.getEta()); waitRef.set(unavail.getWait()); tokenRef.set(unavail.getToken()); return Mono.empty(); } }).repeatWhenEmpty(Repeat .onlyIf(ctx -> true) .doOnRepeat(ctx -> println(waitRef.get() + ", " + etaRef.get() + ", " + tokenRef.get()))); }
  18. class StateMachineIterator implements Iterator<String> { private int state; private int

    i; public String next() { switch(state) { case 0: state=1; return "A"; case 1: state=2; i=0; return "B"; case 2: if(i == 3) state = 3; return "C" + (i++); case 3: state=4; return "D"; case 4: state=5; return "E"; default: throw new NoSuchElementException(); } } public boolean hasNext() { return state < 5; } public void remove() { throw new UnsupportedOperationException("Not supported"); } }
  19. class StateMachineIterator implements Iterator<String> { private int state; private int

    i; public String next() { switch(state) { case 0: state=1; return "A"; case 1: state=2; i=0; return "B"; case 2: if(i == 3) state = 3; return "C" + (i++); case 3: state=4; return "D"; case 4: state=5; return "E"; default: throw new NoSuchElementException(); } } public boolean hasNext() { return state < 5; } public void remove() { throw new UnsupportedOperationException("Not supported"); } }
  20. class StateMachineIterator implements Iterator<String> { private int state; private int

    i; public String next() { switch(state) { case 0: state=1; return "A"; case 1: state=2; i=0; return "B"; case 2: if(i == 3) state = 3; return "C" + (i++); case 3: state=4; return "D"; case 4: state=5; return "E"; default: throw new NoSuchElementException(); } } public boolean hasNext() { return state < 5; } public void remove() { throw new UnsupportedOperationException("Not supported"); } }
  21. class StateMachineIterator implements Iterator<String> { private int state; private int

    i; public String next() { switch(state) { case 0: state=1; return "A"; case 1: state=2; i=0; return "B"; case 2: if(i == 3) state = 3; return "C" + (i++); case 3: state=4; return "D"; case 4: state=5; return "E"; default: throw new NoSuchElementException(); } } public boolean hasNext() { return state < 5; } public void remove() { throw new UnsupportedOperationException("Not supported"); } }
  22. private Connection.Available getConnection(long eta, long wait, String token) { for(;;)

    { if (eta > MAX_ETA_MS) { throw new EtaExceededException(); } if (wait > 0) { Thread.sleep(wait); } println("Retrying download after " + wait + "ms wait."); Connection c = coordinator.requestConnection(token); if (c instanceof Connection.Available) { return (Connection.Available) c; } Connection.Unavailable unavail = (Connection.Unavailable) c; eta = unavail.getEta(); wait = unavail.getWait(); token = unavail.getToken(); } }
  23. Connection.Available conn = getConnection(); Runnable pulse = makePulse(conn); Fiber<Object> f

    = null; try (InputStream content = gateway.downloadThingy()) { f = FiberScope.background().schedule(pulse); ignoreContent(content); } catch (IOException e) { err("Download failed."); throw e; } finally { if (f!=null) { f.cancel(); } }
  24. Papers and Webpages Flynn, Michael J. - Some Computer Organizations

    and Their Effectiveness Haynes, Christopher T. - Logic Continuations Wand, Mitchell - Continuation-based Multiprocessing Loitsch, Florian - Exceptional Continuations in JavaScript Long, James - What's In A Continuation Reynolds, John C. - The Discoveries of Continuations Clinger, Hartheimer, Ost - Implementation Strategies for Continuations Haynes, Friedman, Wand - Obtaining Coroutines with Continuations Pressler, Ron - Why Continuations are Coming to Java Repos https://github.com/forax/loom-fiber/ https://bitbucket.org/arnaudbos/untangled/