/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util.async; /** * Utility allowing operations to be implemented in blocking forms by default with a non-blocking mode. If blocking operations (the default) are off then a method may throw this exception in order to * indicate a non-blocking failure. The stack frame that most recently disabled blocking exceptions on that thread may then handle the exception. * <p> * It is only normally wise to disable blocking operations for tasks that are read-only as an otherwise atomic write task could leave the system in an inconsistent state if the blocking exception is * thrown by one of its component tasks. */ public final class BlockingOperation extends Error { private static final long serialVersionUID = 1L; private static final class TLS { private int _offCount; } private static final ThreadLocal<TLS> s_tls = new ThreadLocal<TLS>() { @Override protected TLS initialValue() { return new TLS(); } }; private BlockingOperation() { } /** * Disable blocking operations for the calling thread. This must be matched by a later call to {@link #on}. If blocking operations are already disabled they remain disabled and an internal counter * will ensure they will stay off after the corresponding call to {@code on}. */ public static void off() { assert s_tls.get()._offCount >= 0; s_tls.get()._offCount++; } /** * Restore blocking operations for the calling thread. This must be matched by an earlier call to {@link #off}. If blocking operations were already disabled at the preceding call to {@code off} they * will remain off. */ public static void on() { assert s_tls.get()._offCount > 0; s_tls.get()._offCount--; } /** * If blocking operations are disabled this will throw a {@link BlockingOperation} exception instance. Otherwise this is a no-op. */ public static void wouldBlock() { if (isOff()) { throw block(); } } /** * Tests if blocking operations (the default) are enabled. * * @return true if operations must block, false if they may throw an exception instead. */ public static boolean isOn() { return s_tls.get()._offCount == 0; } /** * Tests if blocking operations are disabled. * * @return true if operations may throw an exception, false if they must block */ public static boolean isOff() { return s_tls.get()._offCount != 0; } public static BlockingOperation block() { assert isOff(); return new BlockingOperation(); } }