public boolean block ( final long identifier , final Runnable asyncProcessor ) throws InterruptedException , InvalidIdentifierException { final ComplexCondition call = allocate ( ) ; if ( call . isHeldByCurrentThread ( ) ) { throw new RuntimeException ( "release() must not be called on same thread as block() to prevent deadlock" ) ; } try { call . lock ( ) ; // Add the call identifier to the sleeper map so release() can identify this instantiation. addSleeper ( identifier , call ) ; // Invoke the caller's asynchronous processing while holding the lock // so a wakeup cannot occur before the caller sleeps. if ( executor == null ) { asyncProcessor . run ( ) ; } else { executor . execute ( asyncProcessor ) ; } // Put the caller to sleep until the ack comes back. Note: we atomically // give up the look as the caller sleeps and atomically reacquire the // the lock as we wake up. LOG . log ( Level . FINER , "Putting caller to sleep on identifier [{0}]" , identifier ) ; final boolean timeoutOccurred = ! call . await ( ) ; if ( timeoutOccurred ) { LOG . log ( Level . WARNING , "Call timed out on identifier [{0}]" , identifier ) ; } return timeoutOccurred ; } finally { // Whether or not the call completed successfully, always remove // the call from the sleeper map, release the lock and cleanup. try { removeSleeper ( identifier ) ; recycle ( call ) ; } finally { call . unlock ( ) ; } } }
Put the caller to sleep on a specific release identifier .