CompeteLatch.java |
1 /** 2 * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved. 3 * 4 * 5 * 6 * 7 * The contents of this file are subject to the terms of the Liferay Enterprise 8 * Subscription License ("License"). You may not use this file except in 9 * compliance with the License. You can obtain a copy of the License by 10 * contacting Liferay, Inc. See the License for the specific language governing 11 * permissions and limitations under the License, including but not limited to 12 * distribution rights of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23 package com.liferay.portal.kernel.concurrent; 24 25 import java.util.concurrent.locks.AbstractQueuedSynchronizer; 26 27 /** 28 * <a href="CompeteLatch.java.html"><b><i>View Source</i></b></a> 29 * 30 * <p> 31 * A synchronizer based on the JDK's AQS framework to simulate a single winner 32 * competition. This synchronizer supports cyclical competition. In this 33 * situation, loser threads should try again. The single winner thread will lock 34 * the latch while other threads will block on the latch by calling 35 * <code>await</code>. After the winner thread finishes its job, it should call 36 * <code>done</code> which will open the latch. All blocking loser threads can 37 * pass the latch at the same time. 38 * </p> 39 * 40 * <p> 41 * See LPS-3744 for a sample use case. 42 * </p> 43 * 44 * @author Shuyang Zhou 45 */ 46 public class CompeteLatch { 47 48 /** 49 * This method should only be called by a loser thread. If the latch is 50 * locked, that means the winner is executing its job and all loser threads 51 * that call this method will be blocked. If the latch is not locked, that 52 * means the winner has finished its job and all the loser threads calling 53 * this method will return immediately. If the winner thread calls this 54 * method before his job completed, then all threads will deadlock. 55 */ 56 public void await() { 57 _sync.acquireShared(1); 58 } 59 60 /** 61 * Tells the current thread to join the competition. Return immediately 62 * whether or not the current thread is the winner thread or a loser thread. 63 * No matter how many threads join this competition, only one thread can be 64 * the winner thread. 65 * 66 * @return true if the current thread is the winner thread 67 */ 68 public boolean compete() { 69 return _sync._tryInitAcquireShared(); 70 } 71 72 /** 73 * This method should only be called by the winner thread. The winner thread 74 * calls this method to indicate that it has finished its job and unlocks 75 * the latch to allow all loser threads return from the <code>await</code> 76 * method. If a loser thread does call this method when a winner thread has 77 * locked the latch, the latch will break and the winner thread may be put 78 * into a non thread safe state. You should never have to do this except to 79 * get out of a deadlock. If no one threads have locked the latch, then 80 * calling this method has no effect. This method will return immediately. 81 * 82 * @return true if this call opens the latch, false if the latch is already 83 * open 84 */ 85 public boolean done() { 86 return _sync.releaseShared(1); 87 } 88 89 /** 90 * Returns true if the latch is locked. This method should not be used to 91 * test the latch before joining a competition because it is not thread 92 * safe. The only purpose for this method is to give external systems a way 93 * to monitor the latch which is usually be used for deadlock detection. 94 */ 95 public boolean isLocked() { 96 return _sync._isLocked(); 97 } 98 99 private Sync _sync = new Sync(); 100 101 private class Sync extends AbstractQueuedSynchronizer { 102 103 protected int tryAcquireShared(int arg) { 104 if (getState() == 0) { 105 return 1; 106 } 107 else { 108 return -1; 109 } 110 } 111 112 protected boolean tryReleaseShared(int arg) { 113 if (compareAndSetState(1, 0)) { 114 return true; 115 } 116 else { 117 return false; 118 } 119 } 120 121 private final boolean _isLocked() { 122 if (getState() == 1) { 123 return true; 124 } 125 else { 126 return false; 127 } 128 } 129 130 private final boolean _tryInitAcquireShared() { 131 if (compareAndSetState(0, 1)) { 132 return true; 133 } 134 else { 135 return false; 136 } 137 } 138 139 } 140 141 }