/
wstartsev
/
jdk
Обзор
Документация
Войти
/
wstartsev
/
jdk
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/java.base/share/classes/java/util/concurrent/Joiners.java
237 строк
8 KB
Alan Bateman
8367857: Implement JEP 525: Structured Concurrency (Sixth Preview)
10 ноя 2025, 19:34
10 ноя 2025, 19:34
0bae56b
Код
Авторство
О чём код?
/* * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.util.concurrent; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.StructuredTaskScope.Joiner; import java.util.concurrent.StructuredTaskScope.Subtask; import java.util.function.Predicate; import jdk.internal.invoke.MhUtil; /** * Built-in StructuredTaskScope.Joiner implementations. */ class Joiners { private Joiners() { } /** * Throws IllegalArgumentException if the subtask is not in the UNAVAILABLE state. */ private static void ensureUnavailable(Subtask<?> subtask) { if (subtask.state() != Subtask.State.UNAVAILABLE) { throw new IllegalArgumentException("Subtask not in UNAVAILABLE state"); } } /** * Throws IllegalArgumentException if the subtask has not completed. */ private static Subtask.State ensureCompleted(Subtask<?> subtask) { Subtask.State state = subtask.state(); if (state == Subtask.State.UNAVAILABLE) { throw new IllegalArgumentException("Subtask has not completed"); } return state; } /** * A joiner that returns a list of all results when all subtasks complete * successfully. Cancels the scope if any subtask fails. */ static final class AllSuccessful<T> implements Joiner<T, List<T>> { private static final VarHandle FIRST_EXCEPTION = MhUtil.findVarHandle(MethodHandles.lookup(), "firstException", Throwable.class); // list of forked subtasks, created lazily, only accessed by owner thread private List<Subtask<T>> subtasks; private volatile Throwable firstException; @Override public boolean onFork(Subtask<T> subtask) { ensureUnavailable(subtask); if (subtasks == null) { subtasks = new ArrayList<>(); } subtasks.add(subtask); return false; } @Override public boolean onComplete(Subtask<T> subtask) { Subtask.State state = ensureCompleted(subtask); return (state == Subtask.State.FAILED) && (firstException == null) && FIRST_EXCEPTION.compareAndSet(this, null, subtask.exception()); } @Override public List<T> result() throws Throwable { Throwable ex = firstException; try { if (ex != null) { throw ex; } return (subtasks != null) ? subtasks.stream().map(Subtask::get).toList() : List.of(); } finally { subtasks = null; // allow subtasks to be GC'ed } } } /** * A joiner that returns the result of the first subtask to complete successfully. * Cancels the scope if any subtasks succeeds. */ static final class AnySuccessful<T> implements Joiner<T, T> { private static final VarHandle SUBTASK = MhUtil.findVarHandle(MethodHandles.lookup(), "subtask", Subtask.class); // UNAVAILABLE < FAILED < SUCCESS private static final Comparator<Subtask.State> SUBTASK_STATE_COMPARATOR = Comparator.comparingInt(AnySuccessful::stateToInt); private volatile Subtask<T> subtask; /** * Maps a Subtask.State to an int that can be compared. */ private static int stateToInt(Subtask.State s) { return switch (s) { case UNAVAILABLE -> 0; case FAILED -> 1; case SUCCESS -> 2; }; } @Override public boolean onComplete(Subtask<T> subtask) { Subtask.State state = ensureCompleted(subtask); Subtask<T> s; while (((s = this.subtask) == null) || SUBTASK_STATE_COMPARATOR.compare(s.state(), state) < 0) { if (SUBTASK.compareAndSet(this, s, subtask)) { return (state == Subtask.State.SUCCESS); } } return false; } @Override public T result() throws Throwable { Subtask<T> subtask = this.subtask; if (subtask == null) { throw new NoSuchElementException("No subtasks completed"); } return switch (subtask.state()) { case SUCCESS -> subtask.get(); case FAILED -> throw subtask.exception(); default -> throw new InternalError(); }; } } /** * A joiner that that waits for all successful subtasks. Cancels the scope if any * subtask fails. */ static final class AwaitSuccessful<T> implements Joiner<T, Void> { private static final VarHandle FIRST_EXCEPTION = MhUtil.findVarHandle(MethodHandles.lookup(), "firstException", Throwable.class); private volatile Throwable firstException; @Override public boolean onComplete(Subtask<T> subtask) { Subtask.State state = ensureCompleted(subtask); return (state == Subtask.State.FAILED) && (firstException == null) && FIRST_EXCEPTION.compareAndSet(this, null, subtask.exception()); } @Override public Void result() throws Throwable { Throwable ex = firstException; if (ex != null) { throw ex; } else { return null; } } } /** * A joiner that returns a list of all subtasks. */ static final class AllSubtasks<T> implements Joiner<T, List<Subtask<T>>> { private final Predicate<Subtask<T>> isDone; // list of forked subtasks, created lazily, only accessed by owner thread private List<Subtask<T>> subtasks; AllSubtasks(Predicate<Subtask<T>> isDone) { this.isDone = Objects.requireNonNull(isDone); } @Override public boolean onFork(Subtask<T> subtask) { ensureUnavailable(subtask); if (subtasks == null) { subtasks = new ArrayList<>(); } subtasks.add(subtask); return false; } @Override public boolean onComplete(Subtask<T> subtask) { ensureCompleted(subtask); return isDone.test(subtask); } @Override public void onTimeout() { // do nothing, this joiner does not throw TimeoutException } @Override public List<Subtask<T>> result() { if (subtasks != null) { List<Subtask<T>> result = List.copyOf(subtasks); subtasks = null; // allow subtasks to be GC'ed return result; } else { return List.of(); } } } }