001    /*
002     * Copyright 2009-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2009-2016 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    }