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 }