j.l.Thread
, j.u.concurrent
goto
with threadsawaitTermination
wait
, notify
, synchronized
java.util.concurrent
ReentrantLock
, ConcurrentHashMap
, Executor
, Future
AsyncTask
/SwingWorker
Thread thread = Thread.startVirtualThread(runnable); // Already started!!!
Thread thread = Thread.builder() .virtual() .name(taskname) .task(runnable) .build();
ExecutorService exec = Executors.newVirtualThreadExecutor(); exec.submit(runnable1); Future<T> result = exec.submit(callable2);
ThreadFactory myfactory = Thread.builder() .virtual() .name("myfactory-", 1) .factory(); ExecutorService exec = Executors.newThreadExecutor(myfactory);
exec = Executors.newCachedThreadPool(myfactory); // Bad idea
final int NTASKS = 1_000_000; ExecutorService exec = Executors.newVirtualThreadExecutor(); for (int i = 1; i <= NTASKS; i++) { exec.submit(() -> run(i)); }
Thread.sleep
makes the current fiber sleep:
public static Void run(Object obj) {
Thread.sleep((int) (DELAY * (0.5 + Math.random())));
System.out.println(obj);
return null; // Pro tip—turns lambda into Callable
}
Thread.sleep
j.u.c
LocksReentrantLock
is ok)goto
go myfunc(); new Thread(this::myfunc).start();
goto
with branches, loops, functions
exec.close()
blocks until all tasks are done
Executor
is autocloseable:
try (ExecutorService exec = Executor.newVirtualThreadExecutor()) { for (int i = 0; i < NTASKS; i++) { exec.schedule(() -> run(i)); } } // Blocks until all threads completed
invokeAny
, invokeAll
ExecutorService exec = Executors.newVirtualThreadExecutor().withDeadline( Instant.now().plus(30, ChronoUnit.SECONDS))
try { . . . while(!done) { if (Thread.interrupted()) throw new InterruptedException(); . . . } } catch (InterruptedException ex) { . . . // Clean up }
ExecutorService.invokeAny
cancels remaining tasksCompletableFuture.anyOf
doesn'tExecutorService.shutdownNow
, expired deadline interrupts remaining taskspublic static ThreadLocal<Connection> connTL = ThreadLocal<>.withInitial(() -> dbManager.openConnection()); // Much later, several function calls deep Connection conn = connTL.get() // Gets the value for the current thread
SimpleDateFormat
Thread.Builder
methods noThreadLocals()
, noInheritableThreadLocals()
LightweightThreadLocal<Connection> connTL = ThreadLocal.forType(Connection.class);
. . .
try (var connection = dbManager.openConnection();
var __ = connTL.bind(connection);
var exec = Executors.newVirtualThreadExecutor()) {
exec.submitTasks(tasks); // The tasks can read connTL
}
try (var __ = connTL.bind(connection)) { userList.parallelStream().forEach(u -> persistUser(u)); }
https://dilbert.com/strip/2011-06-05
CompletableFuture .completedFuture(getUrlForDate(date)) .thenComposeAsync(this::readPage, executor) .thenApply(this::getImageUrl) .thenComposeAsync(this::readPage) .thenAccept(this::process);
try (ExecutorService exec = Executors.newVirtualThreadExecutor()) { LocalDate date = LocalDate.now(); for (int i = 0; i < NUMBER_TO_SHOW; i++) { ImageInfo info = new WikimediaImageInfo(date); exec.submit(() -> load(info)); date = date.minusDays(1); } }
load
Thread.start
, Thread.sleep
Thread.interrupted
, InterruptedException
Thread.join
synchronized
methods, synchronized
blocksvolatile
wait
, notifyAll
Runnable
is a task (presumably with a side effect)Callable<T>
delivers a result (hopefully without side effects)Runnable task = () -> { ... }; ExecutorService exec = ...; exec.execute(task);
Callable<Long> task = () -> { ...; return count; } Future<Long> result = exec.submit(task);
result.get()
blocks.ExecutorService.invokeAll
/invokeAny
for composing resultsCompletableFuture
)synchronized
, notifyAll
, volatile
j.u.concurrent
has ConcurrentHashMap
, LinkedBlockingQueue
, AtomicLong
Semaphore
, CountDownLatch
, CyclicBarrier
, Phaser
?
awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS)
j.u.stream