| 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
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 }