import java.util.concurrent.atomic.AtomicBoolean; public class TryLock { /** * 在 TryLock 的内部,我们借助于 AtomicBoolean 的布尔原子性操作方法 */ private final AtomicBoolean ab = new AtomicBoolean(false); /** * 线程保险箱,用于存放与线程上下文关联的数据副本 */ private final ThreadLocal<Boolean> threadLocal = ThreadLocal.withInitial(()-> false); /** * 可立即返回的 lock 方法 */ public boolean tryLock(){ /** * 借助于 AtomicBoolean 的 CAS 操作对布尔值进行修改 */ boolean result = ab.compareAndSet(false,true); if(result){ /** * 当修改成功的时候,同步更新 threadLocal 的数据副本值 */ threadLocal.set(result); } return result; } /** * 锁的释放 */ public boolean release(){ /** * 判断调用 release 方法的线程是否成功获得了该锁 */ if(threadLocal.get()){ /** * 标记锁被释放,并且原子性地修改布尔值为 false */ threadLocal.set(false); /** * 下面的方法对 ab 当前的布尔值进行 CAS 操作,当预期值与 ab 当前值一致的时候操作才能成功, * 否则操作将直接失败,因此执行该方法的线程不会进入阻塞,这一点是非常关键的。 */ return ab.compareAndSet(true,false); }else{ return false; } } }
--------------------测试代码
import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import static java.lang.Thread.currentThread; public class TryLockExample { private final static Object VAL_OBJ = new Object(); public static void main(String[] args) { /** * 定义 TryLock 锁 */ final TryLock lock = new TryLock(); final List<Object> validation = new ArrayList<Object>(); /** * 启动 10 个线程,并且不断地进行锁的获取和释放操作 */ for(int i = 0 ; i < 10 ; i++){ new Thread(new Runnable() { public void run() { try{ while(true){ /** * 尝试获取该锁,该方法不会导致当前线程进入阻塞 * * currentThread(): Returns a reference to the currently executing thread object. */ if(lock.tryLock()){ System.out.println(currentThread() + ":get the lock"); if( validation.size() > 1){ throw new IllegalStateException("validation failed."); } validation.add(VAL_OBJ); TimeUnit.MILLISECONDS.sleep(2); }else{ System.out.println(currentThread() + ": not get the lock"); // 未获得锁,简单做个休眠,以防止出现 CPU 过高电脑死机的情况发生 TimeUnit.MILLISECONDS.sleep(2); } } }catch(InterruptedException e ){ e.printStackTrace(); }finally { // 在 finally 语句块中进行锁的释放操作 if(lock.release()){ System.out.println(currentThread() + ": release the lock."); validation.remove(VAL_OBJ); } } } }).start(); } } }