001/*
002 * JPPF.
003 * Copyright (C) 2005-2018 JPPF Team.
004 * http://www.jppf.org
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.jppf.utils.concurrent;
020
021import java.io.Serializable;
022import java.util.concurrent.TimeUnit;
023import java.util.concurrent.locks.*;
024
025import org.jppf.utils.SystemUtils;
026
027/**
028 * A non-fair lock implementation that allows assigning a readable and identifiable name and {@code toString()}.
029 * @author Laurent Cohen
030 */
031public class JPPFReentrantLock implements Lock, Serializable {
032  /**
033   * Explicit serial version UID.
034   */
035  private static final long serialVersionUID = 1L;
036  /**
037   * Name given to this lock.
038   */
039  private final String name;
040  /**
041   * Synchronizer providing all implementation mechanics
042   */
043  private final Synchronizer synchronizer;
044
045  /**
046   * Creates an instance of {@code JPPFReentrantLock}.
047   */
048  public JPPFReentrantLock() {
049    this(null);
050  }
051
052  /**
053   * Creates an instance of {@code JPPFReentrantLock}.
054   * @param name the name.
055   */
056  public JPPFReentrantLock(final String name) {
057    synchronizer = new Synchronizer(name);
058    final String s = SystemUtils.getSystemIdentity(this);
059    this.name = (name == null) ? s : s + " [" + name + "]";
060  }
061
062  @Override
063  public void lock() {
064    synchronizer.acquire(1);
065  }
066
067  @Override
068  public void lockInterruptibly() throws InterruptedException {
069    synchronizer.acquireInterruptibly(1);
070  }
071
072  @Override
073  public boolean tryLock() {
074    return synchronizer.tryAcquire(1);
075  }
076
077  @Override
078  public boolean tryLock(final long timeout, final TimeUnit unit) throws InterruptedException {
079    return synchronizer.tryAcquireNanos(1, unit.toNanos(timeout));
080  }
081
082  @Override
083  public void unlock() {
084    synchronizer.release(1);
085  }
086
087  @Override
088  public Condition newCondition() {
089    return synchronizer.newCondition();
090  }
091
092  @Override
093  public String toString() {
094    return name;
095  }
096
097  /**
098   * Object to which locking and synchronization operations are delegated.
099   */
100  static class Synchronizer extends AbstractQueuedSynchronizer {
101    /**
102     * Name given to this synchronizer.
103     */
104    final String name;
105
106    /**
107     * Creates an instance of {@code JPPFReentrantLock}.
108     * @param name the name.
109     */
110    Synchronizer(final String name) {
111      final String s = SystemUtils.getSystemIdentity(this);
112      this.name = (name == null) ? s : s + " [" + name + "]";
113    }
114
115    @Override
116    public boolean tryAcquire(final int arg) {
117      final Thread current = Thread.currentThread();
118      final int currentState = getState();
119      if (currentState == 0) {
120        if (compareAndSetState(0, 1)) {
121          setExclusiveOwnerThread(current);
122          return true;
123        }
124      } else if (getExclusiveOwnerThread() == current) {
125        setState(currentState + 1);
126        return true;
127      }
128      return false;
129    }
130
131    @Override
132    public boolean tryRelease(final int arg) {
133      if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException("thread " + Thread.currentThread() + " does not own this lock");
134      final int newState = getState() - 1;
135      if (newState == 0) {
136        setExclusiveOwnerThread(null);
137        setState(0);
138        return true;
139      }
140      setState(newState);
141      return false;
142    }
143
144    @Override
145    protected boolean isHeldExclusively() {
146      return getExclusiveOwnerThread() == Thread.currentThread();
147    }
148
149    /**
150     * @return a {@link Condition} instance.
151     */
152    Condition newCondition() {
153      return new ConditionObject();
154    }
155
156    @Override
157    public String toString() {
158      return name;
159    }
160  }
161}