com.liferay.portal.kernel.concurrent.CompeteLatch Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of portal-service Show documentation
Show all versions of portal-service Show documentation
Contains interfaces for the portal services. Interfaces are only loaded by the global class loader and are shared by all plugins.
/**
* Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.concurrent;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
/**
* A synchronizer based on the JDK's AQS framework to simulate a single winner
* competition. This synchronizer supports cyclical competition. In this
* situation, loser threads should try again. The single winner thread will lock
* the latch while other threads will block on the latch by calling
* await
. After the winner thread finishes its job, it should call
* done
which will open the latch. All blocking loser threads can
* pass the latch at the same time.
*
*
* See LPS-3744 for a sample use case.
*
*
* @author Shuyang Zhou
*/
public class CompeteLatch {
/**
* This method should only be called by a loser thread. If the latch is
* locked, that means the winner is executing its job and all loser threads
* that call this method will be blocked. If the latch is not locked, that
* means the winner has finished its job and all the loser threads calling
* this method will return immediately. If the winner thread calls this
* method before his job completed, then all threads will deadlock.
*
* @throws InterruptedException if the current thread is interrupted
*/
public void await() throws InterruptedException {
_sync.acquireSharedInterruptibly(1);
}
/**
* This method should only be called by a loser thread. If the latch is
* locked, that means the winner is executing its job and all loser threads
* that call this method will be blocked for the given waiting time. If the
* latch is not locked, that means the winner has finished its job and all
* the loser threads calling this method will return immediately. If the
* winner thread calls this method before his job completed, then all
* threads will deadlock.
*
* @param timeout the timeout value
* @param timeUnit the time unit
* @return true
if the latch was open, false
if
* the waiting time elapsed before the latch be opened.
* @throws InterruptedException if the current thread is interrupted
*/
public boolean await(long timeout, TimeUnit timeUnit)
throws InterruptedException {
return _sync.tryAcquireSharedNanos(1, timeUnit.toNanos(timeout));
}
/**
* Tells the current thread to join the competition. Return immediately
* whether or not the current thread is the winner thread or a loser thread.
* No matter how many threads join this competition, only one thread can be
* the winner thread.
*
* @return true
if the current thread is the winner thread
*/
public boolean compete() {
return _sync._tryInitAcquireShared();
}
/**
* This method should only be called by the winner thread. The winner thread
* calls this method to indicate that it has finished its job and unlocks
* the latch to allow all loser threads return from the await
* method. If a loser thread does call this method when a winner thread has
* locked the latch, the latch will break and the winner thread may be put
* into a non thread safe state. You should never have to do this except to
* get out of a deadlock. If no one threads have locked the latch, then
* calling this method has no effect. This method will return immediately.
*
* @return true
if this call opens the latch,
* false
if the latch is already open
*/
public boolean done() {
return _sync.releaseShared(1);
}
/**
* Returns true
if the latch is locked. This method should not
* be used to test the latch before joining a competition because it is not
* thread safe. The only purpose for this method is to give external systems
* a way to monitor the latch which is usually be used for deadlock
* detection.
*
* @return true
if the latch is locked; false
* otherwise
*/
public boolean isLocked() {
return _sync._isLocked();
}
private Sync _sync = new Sync();
private class Sync extends AbstractQueuedSynchronizer {
@Override
protected int tryAcquireShared(int arg) {
if (getState() == 0) {
return 1;
}
else {
return -1;
}
}
@Override
protected boolean tryReleaseShared(int arg) {
if (compareAndSetState(1, 0)) {
return true;
}
else {
return false;
}
}
private boolean _isLocked() {
if (getState() == 1) {
return true;
}
else {
return false;
}
}
private boolean _tryInitAcquireShared() {
if (compareAndSetState(0, 1)) {
return true;
}
else {
return false;
}
}
}
}