001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. 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 */ 018package org.apache.hadoop.util; 019 020import java.util.concurrent.locks.Lock; 021import java.util.concurrent.locks.Condition; 022import java.util.concurrent.locks.ReentrantLock; 023 024import com.google.common.annotations.VisibleForTesting; 025 026/** 027 * This is a wrap class of a ReentrantLock. Extending AutoCloseable 028 * interface such that the users can use a try-with-resource syntax. 029 */ 030public class AutoCloseableLock implements AutoCloseable { 031 032 private final Lock lock; 033 034 /** 035 * Creates an instance of {@code AutoCloseableLock}, initializes 036 * the underlying lock instance with a new {@code ReentrantLock}. 037 */ 038 public AutoCloseableLock() { 039 this(new ReentrantLock()); 040 } 041 042 /** 043 * Wrap provided Lock instance. 044 * @param lock Lock instance to wrap in AutoCloseable API. 045 */ 046 public AutoCloseableLock(Lock lock) { 047 this.lock = lock; 048 } 049 050 /** 051 * A wrapper method that makes a call to {@code lock()} of the underlying 052 * {@code ReentrantLock} object. 053 * 054 * Acquire teh lock it is not held by another thread, then sets 055 * lock held count to one, then returns immediately. 056 * 057 * If the current thread already holds the lock, increase the lock 058 * help count by one and returns immediately. 059 * 060 * If the lock is held by another thread, the current thread is 061 * suspended until the lock has been acquired by current thread. 062 * 063 * @return The {@code ReentrantLock} object itself. This is to 064 * support try-with-resource syntax. 065 */ 066 public AutoCloseableLock acquire() { 067 lock.lock(); 068 return this; 069 } 070 071 /** 072 * A wrapper method that makes a call to {@code unlock()} of the 073 * underlying {@code ReentrantLock} object. 074 * 075 * Attempts to release the lock. 076 * 077 * If the current thread holds the lock, decrements the hold 078 * count. If the hold count reaches zero, the lock is released. 079 * 080 * If the current thread does not hold the lock, then 081 * {@link IllegalMonitorStateException} is thrown. 082 */ 083 public void release() { 084 lock.unlock(); 085 } 086 087 /** 088 * Attempts to release the lock by making a call to {@code release()}. 089 * 090 * This is to implement {@code close()} method from {@code AutoCloseable} 091 * interface. This allows users to user a try-with-resource syntax, where 092 * the lock can be automatically released. 093 */ 094 @Override 095 public void close() { 096 release(); 097 } 098 099 /** 100 * A wrapper method that makes a call to {@code tryLock()} of 101 * the underlying {@code Lock} object. 102 * 103 * If the lock is not held by another thread, acquires the lock, set the 104 * hold count to one and returns {@code true}. 105 * 106 * If the current thread already holds the lock, the increment the hold 107 * count by one and returns {@code true}. 108 * 109 * If the lock is held by another thread then the method returns 110 * immediately with {@code false}. 111 * 112 * @return {@code true} if the lock was free and was acquired by the 113 * current thread, or the lock was already held by the current 114 * thread; and {@code false} otherwise. 115 */ 116 public boolean tryLock() { 117 return lock.tryLock(); 118 } 119 120 /** 121 * A wrapper method that makes a call to {@code isLocked()} of 122 * the underlying {@code ReentrantLock} object. 123 * 124 * Queries if this lock is held by any thread. This method is 125 * designed for use in monitoring of the system state, 126 * not for synchronization control. 127 * 128 * @return {@code true} if any thread holds this lock and 129 * {@code false} otherwise 130 */ 131 @VisibleForTesting 132 boolean isLocked() { 133 if (lock instanceof ReentrantLock) { 134 return ((ReentrantLock)lock).isLocked(); 135 } 136 throw new UnsupportedOperationException(); 137 } 138 139 /** 140 * See {@link ReentrantLock#newCondition()}. 141 * @return the Condition object 142 */ 143 public Condition newCondition() { 144 return lock.newCondition(); 145 } 146}