| CompeteLatch.java |
1 /**
2 * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License as published by the Free
6 * Software Foundation; either version 2.1 of the License, or (at your option)
7 * any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 * details.
13 */
14
15 package com.liferay.portal.kernel.concurrent;
16
17 import java.util.concurrent.locks.AbstractQueuedSynchronizer;
18
19 /**
20 * <a href="CompeteLatch.java.html"><b><i>View Source</i></b></a>
21 *
22 * <p>
23 * A synchronizer based on the JDK's AQS framework to simulate a single winner
24 * competition. This synchronizer supports cyclical competition. In this
25 * situation, loser threads should try again. The single winner thread will lock
26 * the latch while other threads will block on the latch by calling
27 * <code>await</code>. After the winner thread finishes its job, it should call
28 * <code>done</code> which will open the latch. All blocking loser threads can
29 * pass the latch at the same time.
30 * </p>
31 *
32 * <p>
33 * See LPS-3744 for a sample use case.
34 * </p>
35 *
36 * @author Shuyang Zhou
37 */
38 public class CompeteLatch {
39
40 /**
41 * This method should only be called by a loser thread. If the latch is
42 * locked, that means the winner is executing its job and all loser threads
43 * that call this method will be blocked. If the latch is not locked, that
44 * means the winner has finished its job and all the loser threads calling
45 * this method will return immediately. If the winner thread calls this
46 * method before his job completed, then all threads will deadlock.
47 */
48 public void await() {
49 _sync.acquireShared(1);
50 }
51
52 /**
53 * Tells the current thread to join the competition. Return immediately
54 * whether or not the current thread is the winner thread or a loser thread.
55 * No matter how many threads join this competition, only one thread can be
56 * the winner thread.
57 *
58 * @return true if the current thread is the winner thread
59 */
60 public boolean compete() {
61 return _sync._tryInitAcquireShared();
62 }
63
64 /**
65 * This method should only be called by the winner thread. The winner thread
66 * calls this method to indicate that it has finished its job and unlocks
67 * the latch to allow all loser threads return from the <code>await</code>
68 * method. If a loser thread does call this method when a winner thread has
69 * locked the latch, the latch will break and the winner thread may be put
70 * into a non thread safe state. You should never have to do this except to
71 * get out of a deadlock. If no one threads have locked the latch, then
72 * calling this method has no effect. This method will return immediately.
73 *
74 * @return true if this call opens the latch, false if the latch is already
75 * open
76 */
77 public boolean done() {
78 return _sync.releaseShared(1);
79 }
80
81 /**
82 * Returns true if the latch is locked. This method should not be used to
83 * test the latch before joining a competition because it is not thread
84 * safe. The only purpose for this method is to give external systems a way
85 * to monitor the latch which is usually be used for deadlock detection.
86 */
87 public boolean isLocked() {
88 return _sync._isLocked();
89 }
90
91 private Sync _sync = new Sync();
92
93 private class Sync extends AbstractQueuedSynchronizer {
94
95 protected int tryAcquireShared(int arg) {
96 if (getState() == 0) {
97 return 1;
98 }
99 else {
100 return -1;
101 }
102 }
103
104 protected boolean tryReleaseShared(int arg) {
105 if (compareAndSetState(1, 0)) {
106 return true;
107 }
108 else {
109 return false;
110 }
111 }
112
113 private final boolean _isLocked() {
114 if (getState() == 1) {
115 return true;
116 }
117 else {
118 return false;
119 }
120 }
121
122 private final boolean _tryInitAcquireShared() {
123 if (compareAndSetState(0, 1)) {
124 return true;
125 }
126 else {
127 return false;
128 }
129 }
130
131 }
132
133 }