All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.coherence.common.base.SingleWaiterMultiNotifier Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */

package com.oracle.coherence.common.base;


import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.concurrent.locks.LockSupport;


/**
 * A Condition-like object, used by a single thread to block for a
 * notification, and optimized for many concurrent notifications by other
 * threads. Basically, this is a blocking queue without any state to
 * actually enqueue: the {@link SingleWaiterMultiNotifier#await()} method
 * is analogous to an imaginary "take all" variant of the
 * {@link java.util.concurrent.BlockingQueue#take() BlockingQueue.take()}
 * method, and the
 * {@link SingleWaiterMultiNotifier#signal()} method is analogous to
 * {@link java.util.concurrent.BlockingQueue#put(Object)
 * BlockingQueue.put()}.
 * 

* Note that no synchronization is needed to use this class; i.e. clients * must not synchronize on this class prior to calling await() or * signal(), nor should the use any of the primitive wait() * or notify() methods. *

* Since SingleWaiterMultiNotifier is only usable by a single waiting thread it is * does not require an external readiness check, as signaling can record that state. * * @author cp/mf 2010-06-15 */ public class SingleWaiterMultiNotifier implements Notifier { @Override public void await(long cMillis) throws InterruptedException { if (m_oState == this) { // pre-signaled; extra volatile read is "free" as compared to CAS // volatile write is same roughly the same cost as CAS // overall this path is about 2x faster then the equivalent pre-signaled CAS path consumeSignal(); } else if (s_fuState.compareAndSet(this, null, Thread.currentThread())) { if (cMillis == 0) { Blocking.park(/*blocker*/ this); } else { Blocking.parkNanos(/*blocker*/ this, cMillis * 1000000); } if (m_oState != this && Blocking.interrupted()) // only pay the cost of interrupt check if we were not signaled { consumeSignal(); throw new InterruptedException(); } consumeSignal(); } else if (m_oState == this) { // concurrently signaled consumeSignal(); } else // m_oState references another thread (or null) { // note, even if m_oState is null we have an error as it could only happen because another // thread had concurrently awaited, which is not safe and could leave one of the thread stuck throw new IllegalStateException("unexpected thread '" + m_oState + "' is also awaiting"); } } @Override public void signal() { LockSupport.unpark(signalInternal()); } // ----- Object interface ----------------------------------------------- @Override public String toString() { Object oState = m_oState; return super.toString() + (oState == this ? " signaled" : " unsignaled(" + /*Thread*/ oState + ")"); } // ----- helpers -------------------------------------------------------- /** * Return the thread which is waiting on this notifier. * * @return the waiting thread or null */ public Thread getWaitingThread() { Object oState = m_oState; return oState == null || oState == this ? null : (Thread) oState; } /** * Signal the notifier returning any thread which needs to be unparked. * * @return a the thread if any which needs to be unparked. */ protected Thread signalInternal() { // from a performance perspective we want to minimize the number of CASs and thread wakeups // we can optimize out repeated/concurrent signals as well as signals which occur concurrently // with a thread wakeing up, we cannot optimize out signals which occur concurrentlly with a // thread going into await Object oState = m_oState; if (oState == null) { if (s_fuState.compareAndSet(this, null, /*signaled*/ this)) { // not yet signaled, no thread was waiting return null; } // else new waiter or concurrent signal; fall through oState = m_oState; } if (oState != this && oState != null && s_fuState.compareAndSet(this, /*thread*/ oState, /*signaled*/ this)) { // we've signled a waiting thread return (Thread) oState; } else { // already signaled, concurrently signal, or thread concurrently awoke return null; } } /** * Consume the signal. */ protected void consumeSignal() { m_oState = null; } // ----- data members --------------------------------------------------- /** * The signaling state, null for unsignaled, this for signaled, or a thread for the single awaiting thread */ protected volatile Object m_oState; /** * The atomic field updater for {@link #m_oState}. */ private static final AtomicReferenceFieldUpdater s_fuState = AtomicReferenceFieldUpdater.newUpdater(SingleWaiterMultiNotifier.class, Object.class, "m_oState"); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy