CompeteLatch.java |
1 /** 2 * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions 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 34 * lock 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 */ 47 public class CompeteLatch { 48 49 /** 50 * This method should only be called by a loser thread. If the latch is 51 * locked, that means the winner is executing its job and all loser threads 52 * that call this method will be blocked. If the latch is not locked, that 53 * means the winner has finished its job and all the loser threads calling 54 * this method will return immediately. If the winner thread calls this 55 * method before his job completed, then all threads will deadlock. 56 */ 57 public void await() { 58 _sync.acquireShared(1); 59 } 60 61 /** 62 * Tells the current thread to join the competition. Return immediately 63 * whether or not the current thread is the winner thread or a loser thread. 64 * No matter how many threads join this competition, only one thread can be 65 * the winner thread. 66 * 67 * @return true if the current thread is the winner thread 68 */ 69 public boolean compete() { 70 return _sync._tryInitAcquireShared(); 71 } 72 73 /** 74 * This method should only be called by the winner thread. The winner thread 75 * calls this method to indicate that it has finished its job and unlocks 76 * the latch to allow all loser threads return from the <code>await</code> 77 * method. If a loser thread does call this method when a winner thread has 78 * locked the latch, the latch will break and the winner thread may be put 79 * into a non thread safe state. You should never have to do this except to 80 * get out of a deadlock. If no one threads have locked the latch, then 81 * calling this method has no effect. This method will return immediately. 82 * 83 * @return true if this call opens the latch, false if the latch is 84 * already open 85 */ 86 public boolean done() { 87 return _sync.releaseShared(1); 88 } 89 90 /** 91 * Returns true if the latch is locked. This method should not be used to 92 * test the latch before joining a competition because it is not thread 93 * safe. The only purpose for this method is to give external systems a way 94 * to monitor the latch which is usually be used for deadlock detection. 95 */ 96 public boolean isLocked(){ 97 return _sync._isLocked(); 98 } 99 100 private Sync _sync = new Sync(); 101 102 private class Sync extends AbstractQueuedSynchronizer { 103 104 protected int tryAcquireShared(int arg) { 105 if (getState() == 0) { 106 return 1; 107 } 108 else { 109 return -1; 110 } 111 } 112 113 protected boolean tryReleaseShared(int arg) { 114 if (compareAndSetState(1, 0)) { 115 return true; 116 } 117 else { 118 return false; 119 } 120 } 121 122 private final boolean _isLocked(){ 123 if (getState() == 1) { 124 return true; 125 } 126 else { 127 return false; 128 } 129 } 130 131 private final boolean _tryInitAcquireShared() { 132 if (compareAndSetState(0, 1)) { 133 return true; 134 } 135 else { 136 return false; 137 } 138 } 139 140 } 141 142 }