/
githubmirror
/
RxJava
Обзор
Документация
Войти
/
githubmirror
/
RxJava
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
4.x
src/main/java/io/reactivex/rxjava4/internal/schedulers/ScheduledRunnable.java
186 строк
6 KB
David Karnok
4.x: Convert from JUnit 4 to JUnit 6 (#8202)
30 июн 2026, 12:01
Не верифицирован
30 июн 2026, 12:01
531388f
Код
Авторство
О чём код?
/* * Copyright (c) 2016-present, RxJava Contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See * the License for the specific language governing permissions and limitations under the License. */ package io.reactivex.rxjava4.internal.schedulers; import java.io.Serial; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReferenceArray; import io.reactivex.rxjava4.annotations.NonNull; import io.reactivex.rxjava4.disposables.*; import io.reactivex.rxjava4.plugins.RxJavaPlugins; import io.reactivex.rxjava4.schedulers.SchedulerRunnableIntrospection; public final class ScheduledRunnable extends AtomicReferenceArray<Object> implements Runnable, Callable<Object>, Disposable, SchedulerRunnableIntrospection { @Serial private static final long serialVersionUID = -6120223772001106981L; final Runnable actual; final boolean interruptOnCancel; /** Indicates that the parent tracking this task has been notified about its completion. */ static final Object PARENT_DISPOSED = new Object(); /** Indicates dispose() was called from within the run/call method. */ static final Object SYNC_DISPOSED = new Object(); /** Indicates dispose() was called from another thread. */ static final Object ASYNC_DISPOSED = new Object(); static final Object DONE = new Object(); static final int PARENT_INDEX = 0; static final int FUTURE_INDEX = 1; static final int THREAD_INDEX = 2; /** * Creates a ScheduledRunnable by wrapping the given action and setting * up the optional parent. * The underlying future will be interrupted if the task is disposed asynchronously. * @param actual the runnable to wrap, not-null (not verified) * @param parent the parent tracking container or null if none */ public ScheduledRunnable(Runnable actual, DisposableContainer parent) { this(actual, parent, true); } /** * Creates a ScheduledRunnable by wrapping the given action and setting * up the optional parent. * @param actual the runnable to wrap, not-null (not verified) * @param parent the parent tracking container or null if none * @param interruptOnCancel if true, the underlying future will be interrupted when disposing * this task from a different thread than it is running on. */ public ScheduledRunnable(Runnable actual, DisposableContainer parent, boolean interruptOnCancel) { super(3); this.actual = actual; this.interruptOnCancel = interruptOnCancel; this.lazySet(0, parent); } @Override public Object call() { // Being Callable saves an allocation in ThreadPoolExecutor run(); return null; } @Override public void run() { lazySet(THREAD_INDEX, Thread.currentThread()); try { try { actual.run(); } catch (Throwable e) { // Exceptions.throwIfFatal(e); nowhere to go RxJavaPlugins.onError(e); throw e; } } finally { Object o = get(PARENT_INDEX); if (o != PARENT_DISPOSED && compareAndSet(PARENT_INDEX, o, DONE) && o != null) { ((DisposableContainer)o).delete(this); } for (;;) { o = get(FUTURE_INDEX); if (o == SYNC_DISPOSED || o == ASYNC_DISPOSED || compareAndSet(FUTURE_INDEX, o, DONE)) { break; } } lazySet(THREAD_INDEX, null); } } public void setFuture(Future<?> f) { for (;;) { Object o = get(FUTURE_INDEX); if (o == DONE) { return; } if (o == SYNC_DISPOSED) { f.cancel(false); return; } if (o == ASYNC_DISPOSED) { f.cancel(interruptOnCancel); return; } if (compareAndSet(FUTURE_INDEX, o, f)) { return; } } } @Override public void dispose() { for (;;) { Object o = get(FUTURE_INDEX); if (o == DONE || o == SYNC_DISPOSED || o == ASYNC_DISPOSED) { break; } boolean async = get(THREAD_INDEX) != Thread.currentThread(); if (compareAndSet(FUTURE_INDEX, o, async ? ASYNC_DISPOSED : SYNC_DISPOSED)) { if (o != null) { ((Future<?>)o).cancel(async && interruptOnCancel); } break; } } for (;;) { Object o = get(PARENT_INDEX); if (o == DONE || o == PARENT_DISPOSED || o == null) { return; } if (compareAndSet(PARENT_INDEX, o, PARENT_DISPOSED)) { ((DisposableContainer)o).delete(this); return; } } } @Override public boolean isDisposed() { Object o = get(PARENT_INDEX); return o == PARENT_DISPOSED || o == DONE; } @Override public String toString() { String state; Object o = get(FUTURE_INDEX); if (o == DONE) { state = "Finished"; } else if (o == SYNC_DISPOSED) { state = "Disposed(Sync)"; } else if (o == ASYNC_DISPOSED) { state = "Disposed(Async)"; } else { o = get(THREAD_INDEX); if (o == null) { state = "Waiting"; } else { state = "Running on " + o; } } return getClass().getSimpleName() + "[" + state + "]"; } @Override public @NonNull Runnable getWrappedRunnable() { return actual; } }