001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.concurrent;
016    
017    import java.util.concurrent.locks.AbstractQueuedSynchronizer;
018    
019    /**
020     * <p>
021     * A synchronizer based on the JDK's AQS framework to simulate a single winner
022     * competition. This synchronizer supports cyclical competition. In this
023     * situation, loser threads should try again. The single winner thread will lock
024     * the latch while other threads will block on the latch by calling
025     * <code>await</code>. After the winner thread finishes its job, it should call
026     * <code>done</code> which will open the latch. All blocking loser threads can
027     * pass the latch at the same time.
028     * </p>
029     *
030     * <p>
031     * See LPS-3744 for a sample use case.
032     * </p>
033     *
034     * @author Shuyang Zhou
035     */
036    public class CompeteLatch {
037    
038            /**
039             * This method should only be called by a loser thread. If the latch is
040             * locked, that means the winner is executing its job and all loser threads
041             * that call this method will be blocked. If the latch is not locked, that
042             * means the winner has finished its job and all the loser threads calling
043             * this method will return immediately. If the winner thread calls this
044             * method before his job completed, then all threads will deadlock.
045             */
046            public void await() {
047                    _sync.acquireShared(1);
048            }
049    
050            /**
051             * Tells the current thread to join the competition. Return immediately
052             * whether or not the current thread is the winner thread or a loser thread.
053             * No matter how many threads join this competition, only one thread can be
054             * the winner thread.
055             *
056             * @return <code>true</code> if the current thread is the winner thread
057             */
058            public boolean compete() {
059                    return _sync._tryInitAcquireShared();
060            }
061    
062            /**
063             * This method should only be called by the winner thread. The winner thread
064             * calls this method to indicate that it has finished its job and unlocks
065             * the latch to allow all loser threads return from the <code>await</code>
066             * method. If a loser thread does call this method when a winner thread has
067             * locked the latch, the latch will break and the winner thread may be put
068             * into a non thread safe state. You should never have to do this except to
069             * get out of a deadlock. If no one threads have locked the latch, then
070             * calling this method has no effect. This method will return immediately.
071             *
072             * @return true if this call opens the latch, <code>false</code> if the
073             *                 latch is already open
074             */
075            public boolean done() {
076                    return _sync.releaseShared(1);
077            }
078    
079            /**
080             * Returns <code>true</code> if the latch is locked. This method should not
081             * be used to test the latch before joining a competition because it is not
082             * thread safe. The only purpose for this method is to give external systems
083             * a way to monitor the latch which is usually be used for deadlock
084             * detection.
085             */
086            public boolean isLocked() {
087                    return _sync._isLocked();
088            }
089    
090            private Sync _sync = new Sync();
091    
092            private class Sync extends AbstractQueuedSynchronizer {
093    
094                    protected int tryAcquireShared(int arg) {
095                            if (getState() == 0) {
096                                    return 1;
097                            }
098                            else {
099                                    return -1;
100                            }
101                    }
102    
103                    protected boolean tryReleaseShared(int arg) {
104                            if (compareAndSetState(1, 0)) {
105                                    return true;
106                            }
107                            else {
108                                    return false;
109                            }
110                    }
111    
112                    private final boolean _isLocked() {
113                            if (getState() == 1) {
114                                    return true;
115                            }
116                            else {
117                                    return false;
118                            }
119                    }
120    
121                    private final boolean _tryInitAcquireShared() {
122                            if (compareAndSetState(0, 1)) {
123                                    return true;
124                            }
125                            else {
126                                    return false;
127                            }
128                    }
129    
130            }
131    
132    }