001 /* 002 * Copyright 2009-2015 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005 /* 006 * Copyright (C) 2009-2015 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021 package com.unboundid.util; 022 023 024 025 import java.io.Serializable; 026 import java.util.concurrent.atomic.AtomicBoolean; 027 import java.util.concurrent.atomic.AtomicLong; 028 029 030 031 /** 032 * This class provides a utility that can be used to sleep for a specified 033 * period of time in a manner that allows it to be woken up if necessary. A 034 * single instance of this class may only be used to allow one thread to sleep 035 * at any given time, so if multiple threads need to sleep at the same time then 036 * a separate {@code WakeableSleeper} instance should be used for each. 037 */ 038 public final class WakeableSleeper 039 implements Serializable 040 { 041 /** 042 * The serial version UID for this serializable class. 043 */ 044 private static final long serialVersionUID = 755656862953269760L; 045 046 047 048 // A flag used to prevent multiple concurrent attempts to sleep. 049 private final AtomicBoolean sleeping; 050 051 // A flag used to indicate that this WakeableSleeper has been shut down. 052 private final AtomicBoolean shutDown; 053 054 // The number of attempts to wake up this sleeper. 055 private final AtomicLong wakeupCount; 056 057 058 059 /** 060 * Creates a new instance of this wakeable sleeper. 061 */ 062 public WakeableSleeper() 063 { 064 sleeping = new AtomicBoolean(false); 065 shutDown = new AtomicBoolean(false); 066 wakeupCount = new AtomicLong(0L); 067 } 068 069 070 071 /** 072 * Return {@code true} if this {@code WakeableSleeper} instance has been 073 * shutdown via the {@code shutDown()} method and {@code false} otherwise. 074 * 075 * @return {@code true} if this {@code WakeableSleeper} instance has been 076 * shutdown via the {@code shutDown()} method and {@code false} 077 * otherwise. 078 */ 079 public boolean isShutDown() 080 { 081 return shutDown.get(); 082 } 083 084 085 086 /** 087 * Attempts to sleep for the specified length of time in milliseconds, subject 088 * to the accuracy available within the JVM and underlying system. It may 089 * wake up prematurely if the wakeup method is called, or if the thread is 090 * interrupted. If {@code shutDown()} is called, then any active caller of 091 * this method will return immediately, and subsequent calls will return 092 * without sleeping. 093 * <BR><BR> 094 * This method must not be called on the same {@code WakeableSleeper} instance 095 * by multiple threads at the same time. 096 * 097 * @param time The length of time in milliseconds to sleep. 098 * 099 * @return {@code true} if the sleep completed, or {@code false} if it was 100 * woken or interrupted prematurely. 101 */ 102 public boolean sleep(final long time) 103 { 104 synchronized (wakeupCount) 105 { 106 if (isShutDown()) 107 { 108 return false; 109 } 110 111 Validator.ensureTrue(sleeping.compareAndSet(false, true), 112 "WakeableSleeper.sleep() must not be invoked concurrently by " + 113 "multiple threads against the same instance."); 114 115 try 116 { 117 final long beforeCount = wakeupCount.get(); 118 wakeupCount.wait(time); 119 final long afterCount = wakeupCount.get(); 120 return (beforeCount == afterCount); 121 } 122 catch (final InterruptedException ie) 123 { 124 Debug.debugException(ie); 125 return false; 126 } 127 finally 128 { 129 sleeping.set(false); 130 } 131 } 132 } 133 134 135 136 /** 137 * Permanently shuts down this {@code WakeableSleeper} instance. If a thread 138 * is currently blocked in the {@code sleep} method, it will return 139 * immediately, and all subsequent calls to that method will return without 140 * sleeping. It is safe to call this method multiple times. 141 */ 142 public void shutDown() 143 { 144 shutDown.set(true); 145 wakeup(); 146 } 147 148 149 150 /** 151 * Indicates that the sleeper should wake up if it is currently sleeping. 152 * This method will not make any attempt to ensure that the thread had woken 153 * up before returning. If multiple threads attempt to wake up the sleeper at 154 * the same time, then it will have the same effect as a single wakeup 155 * request. 156 */ 157 public void wakeup() 158 { 159 synchronized (wakeupCount) 160 { 161 wakeupCount.incrementAndGet(); 162 wakeupCount.notifyAll(); 163 } 164 } 165 }