| /* |
| * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package nsk.share; |
| |
| import java.io.PrintStream; |
| |
| /** |
| * Wicket provides a means for one or more threads to suspend execution |
| * (to wait) until notified by one or more other threads that some set |
| * of locks is now open. |
| * |
| * <p>Wicket instances are intended to be used generally in the following |
| * scenarios: |
| * |
| * <ul><li>One thread starts one or more child threads and waits until the |
| * child threads to be started. |
| * |
| * <li>One thread starts one or more child threads and waits until at least |
| * one of the child threads to be started. |
| * |
| * <li>One or more child threads wait until a main thread lets them |
| * to finish. |
| * |
| * <li>Disable the current thread for thread scheduling purposes, for up to |
| * the specified waiting time.</ul> |
| */ |
| |
| public class Wicket { |
| |
| /** Number of closed locks, can be greater or equal to zero */ |
| private int count; |
| |
| /** Number of waiters **/ |
| private int waiters = 0; |
| |
| /** Enable debug output */ |
| private PrintStream debugOutput = null; |
| |
| /** Wicket's string identifier */ |
| private String name = ""; |
| |
| /** |
| * Construct a Wicket with only one closed lock. |
| */ |
| public Wicket() { |
| this(1); |
| } |
| |
| /** |
| * Construct a Wicket with the given number of closed locks. |
| * |
| * @param _name Wicket's identifier |
| * @param _count the initial number of closed locks |
| * @param _debugOutput whether to print debug info or not |
| * @throws IllegalArgumentException if count is less than 1 |
| */ |
| public Wicket(String _name, int _count, PrintStream _debugOutput) { |
| this(_count); |
| name = _name; |
| debugOutput = _debugOutput; |
| } |
| |
| /** |
| * Construct a Wicket with the given number of closed locks. |
| * |
| * @param count the initial number of closed locks |
| * @throws IllegalArgumentException if count is less than 1 |
| */ |
| public Wicket(int count) { |
| if (count < 1) |
| throw new IllegalArgumentException( |
| "count is less than one: " + count); |
| this.count = count; |
| } |
| |
| /** |
| * Wait for all locks of this Wicket to be open. |
| * |
| * <p>If all locks are already open then returns immediately. |
| * |
| * <p>If at least one lock is still closed then the current thread becomes |
| * disabled for thread scheduling purposes and lies dormant until all |
| * the locks will be open by some other threads. One lock can be open |
| * by invoking the unlock method for this Wicket. |
| * |
| * <p>Please note, that the method would ignore Thread.interrupt() requests. |
| */ |
| public synchronized void waitFor() { |
| ++waiters; |
| if (debugOutput != null) { |
| debugOutput.printf("Wicket %s: waitFor()\n", name); |
| } |
| |
| while (count > 0) { |
| try { |
| wait(); |
| } catch (InterruptedException e) {} |
| } |
| --waiters; |
| } |
| |
| /** |
| * Wait for all locks of this Wicket to be open within the given |
| * period of time. |
| * |
| * <p>If all locks are already open then returns immediately with zero. |
| * |
| * <p>If the time is equal to zero, the method will not |
| * wait and returns a number of closed locks, |
| * if all locks are open, the return value is zero. |
| * |
| * <p>If at least one lock is still closed then the current thread becomes |
| * disabled for thread scheduling purposes and lies dormant until |
| * of the two things happens: |
| * |
| * <ul><li>Some other threads invoke the unlock method for this Wicket |
| * to open all the closed locks; or |
| * |
| * <li>The specified waiting time elapses.</ul> |
| * |
| * <p>If all locks are open then the return value is 0. |
| * |
| * <p>If the specified waiting time elapses and some locks are still closed |
| * then the return value is equal to number of closed locks. |
| * |
| * <p>Please note, that the method would ignore Thread.interrupt() requests. |
| * |
| * @param timeout the maximum time to wait in milliseconds |
| * @return the number of closed locks |
| * @throws IllegalArgumentException if timeout is less than 0 |
| */ |
| public synchronized int waitFor(long timeout) { |
| if (debugOutput != null) { |
| debugOutput.printf("Wicket %s: waitFor(%d)\n", name, timeout); |
| } |
| |
| if (timeout < 0) |
| throw new IllegalArgumentException( |
| "timeout value is negative: " + timeout); |
| ++waiters; |
| long waitTime = timeout; |
| long startTime = System.currentTimeMillis(); |
| while (count > 0 && waitTime > 0) { |
| try { |
| wait(waitTime); |
| } catch (InterruptedException e) {} |
| waitTime = timeout - (System.currentTimeMillis() - startTime); |
| } |
| --waiters; |
| return (count); |
| } |
| |
| /** |
| * Unlock one closed lock. |
| * |
| * <p>Open a lock, reducing the number of closed locks by one. |
| * |
| * <p>If last closed lock is opened then all of the threads waiting |
| * by invoking the waitFor method for this Wicket will be released |
| * and re-enabled for thread scheduling purposes. |
| * |
| * @throws IllegalStateException if there is no one closed lock |
| */ |
| public synchronized void unlock() { |
| if (debugOutput != null) { |
| debugOutput.printf("Wicket %s: unlock()\n", name); |
| } |
| |
| if (count == 0) |
| throw new IllegalStateException("locks are already open"); |
| |
| --count; |
| if (count == 0) { |
| notifyAll(); |
| } |
| } |
| |
| /** |
| * Unlock all closed locks. |
| * |
| * <p>Open all closed locks, setting the number of closed locks to zero. |
| * |
| * <p>If any threads are waiting by invoking the waitFor method for |
| * this Wicket then they will be released and re-enabled for thread |
| * scheduling purposes. |
| */ |
| public synchronized void unlockAll() { |
| if (debugOutput != null) { |
| debugOutput.printf("Wicket %s: unlockAll()\n", name); |
| } |
| |
| count = 0; |
| notifyAll(); |
| } |
| |
| /** |
| * Return current number of waiters - threads that are currently |
| * waiting using one of waitFor methods. |
| * |
| * @return number of waiters |
| */ |
| public synchronized int getWaiters() { |
| if (debugOutput != null) { |
| debugOutput.printf("Wicket %s: getWaiters()\n", name); |
| } |
| return waiters; |
| } |
| } |