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