All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.wildfly.common.lock.SpinLock Maven / Gradle / Ivy

There is a newer version: 2.0.1
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2018 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.wildfly.common.lock;

import static java.lang.invoke.MethodHandles.*;

import java.lang.invoke.ConstantBootstraps;
import java.lang.invoke.VarHandle;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;

import io.smallrye.common.cpu.ProcessorInfo;
import org.wildfly.common.Assert;

/**
 * A spin lock.  Such locks are designed to only be held for a very short time - for example, long enough to compare and
 * swap two fields.  The lock may degrade to yielding the thread after a certain number of spins if it is held for too long.
 * 

* Spin locks do not support conditions, and they do not support timed waiting. Normally only the uninterruptible {@code lock}, * {@code tryLock}, and {@code unlock} methods should be used to control the lock. */ public class SpinLock implements ExtendedLock { private final VarHandle ownerHandle = ConstantBootstraps.fieldVarHandle(lookup(), "owner", VarHandle.class, SpinLock.class, Thread.class); private static final int defaultSpinLimit; static { defaultSpinLimit = AccessController.doPrivileged( (PrivilegedAction) () -> Integer.valueOf( System.getProperty("jboss.spin-lock.limit", ProcessorInfo.availableProcessors() == 1 ? "0" : "5000") ) ).intValue(); } @SuppressWarnings("unused") private volatile Thread owner; private int level; private final int spinLimit; /** * Construct a new instance. */ public SpinLock() { this(defaultSpinLimit); } /** * Construct a new instance with the given spin limit. * * @param spinLimit the spin limit to use for this instance */ public SpinLock(final int spinLimit) { Assert.checkMinimumParameter("spinLimit", 0, spinLimit); this.spinLimit = spinLimit; } /** * Determine if this spin lock is held. Useful for assertions. * * @return {@code true} if the lock is held by any thread, {@code false} otherwise */ public boolean isLocked() { return owner != null; } /** * Determine if this spin lock is held by the calling thread. Useful for assertions. * * @return {@code true} if the lock is held by the calling thread, {@code false} otherwise */ public boolean isHeldByCurrentThread() { return owner == Thread.currentThread(); } /** * Determine if this lock is fair. * * @return {@code true}; the lock is fair */ public boolean isFair() { return true; } /** * Acquire the lock by spinning until it is held. */ public void lock() { Thread owner; int spins = 0; for (;;) { owner = this.owner; if (owner == Thread.currentThread()) { level++; return; } else if (owner == null && trySetOwner()) { level = 1; return; } else if (spins >= spinLimit) { Thread.yield(); } else { Thread.onSpinWait(); spins++; } } } /** * Acquire the lock by spinning until it is held or the thread is interrupted. * * @throws InterruptedException if the thread is interrupted before the lock can be acquired */ public void lockInterruptibly() throws InterruptedException { Thread owner; int spins = 0; for (;;) { if (Thread.interrupted()) throw new InterruptedException(); owner = this.owner; if (owner == Thread.currentThread()) { level++; return; } else if (owner == null && trySetOwner()) { level = 1; return; } else if (spins >= spinLimit) { Thread.yield(); } else { Thread.onSpinWait(); spins++; } } } /** * Try to acquire the lock, returning immediately whether or not the lock was acquired. * * @return {@code true} if the lock was acquired, {@code false} otherwise */ public boolean tryLock() { Thread owner = this.owner; if (owner == Thread.currentThread()) { level++; return true; } else if (owner == null && trySetOwner()) { level = 1; return true; } else { return false; } } /** * Release the lock. * * @throws IllegalMonitorStateException if the lock is not held by the current thread */ public void unlock() { Thread owner = this.owner; if (owner == Thread.currentThread()) { if (--level == 0) this.owner = null; } else { throw new IllegalMonitorStateException(); } } /** * Unsupported. * * @param time ignored * @param unit ignored * @return nothing * @throws UnsupportedOperationException always */ public boolean tryLock(final long time, final TimeUnit unit) throws UnsupportedOperationException { throw Assert.unsupported(); } /** * Unsupported. * * @return nothing * @throws UnsupportedOperationException always */ public Condition newCondition() throws UnsupportedOperationException { throw Assert.unsupported(); } private boolean trySetOwner() { return (boolean) ownerHandle.compareAndSet(this, (Thread) null, Thread.currentThread()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy