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 com.liferay.portal.kernel Show documentation
Show all versions of com.liferay.portal.kernel 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-present 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 final Sync _sync = new Sync();
private static 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;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy