zoukankan      html  css  js  c++  java
  • 使用AQS自定义重入锁

    一、创建MyLock

    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.AbstractQueuedSynchronizer;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    
    public class MyLock implements Lock {
    
        private Helper helper = new Helper();
    
        @Override
        public void lock() {
            helper.acquire(1);
        }
    
        @Override
        public void lockInterruptibly() throws InterruptedException {
            helper.acquireInterruptibly(1);
        }
    
        @Override
        public boolean tryLock() {
            return helper.tryAcquire(1);
        }
    
        @Override
        public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
            return helper.tryAcquireNanos(1, unit.toNanos(time));
        }
    
        @Override
        public void unlock() {
            helper.release(1);
        }
    
        @Override
        public Condition newCondition() {
            return helper.newCondition();
        }
    
        private class Helper extends AbstractQueuedSynchronizer { 
            @Override
            protected boolean tryAcquire(int arg) {
                //如果第一个线程进来,可以拿到锁,返回true
    
                //如果第二个线程进来,拿不到锁,返回false,有种特例,如果当前进来的线程和当前保存的线程是同一个线程,则可以拿到锁,但是要更新状态值
    
                //如何判断是第一个线程进来还是其他线程进来
    
                int state = getState();
                Thread t = Thread.currentThread();
    
                if (state == 0) {//判断是否是第一个线程
                    if (compareAndSetState(0, arg)) {
                        setExclusiveOwnerThread(Thread.currentThread());
                        return true;
                    }
                } else if(getExclusiveOwnerThread() == t) {//判断当前进来的线程和当前保存的线程是否是同一个线程,实现重入锁,因为锁的是对象,所以只要是同一个Helper对象线程就是同一个线程
                    setState(state + 1);
                    return true;
                }
                return false;
            }
    
            @Override
            protected boolean tryRelease(int arg) {
                //锁的获取和释放肯是一一对应的,那么调用此方法的线程一定是当前线程
                if (Thread.currentThread() != getExclusiveOwnerThread()) {
                    throw new RuntimeException();
                }
    
                int state = getState() - arg;
                setState(state);
    
                if (state == 0) {
                    setExclusiveOwnerThread(null);
                    return true;
                }
                return false;
            }
    
            protected ConditionObject newCondition() {
                return new ConditionObject();
            }
    
        }
    }

    二、编写测试代码

    public class TestMyLock {
    
        private int value;
        private MyLock myLock = new MyLock();
    
        public int getValue() {
            myLock.lock();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            value ++;
            myLock.unlock();
            return value;
        }
    
        public void a() {
            myLock.lock();
            System.out.println("a");
            b();
            myLock.unlock();
        }
    
        public void b() {
            myLock.lock();
            System.out.println("b");
            myLock.unlock();
        }
    
        public static void main(String[] args) {
            TestMyLock testMyLock = new TestMyLock();
    
            //检测是否会并发
            Runnable runnable = () -> {
              for (int i = 0; i<100; i++) {
                  System.out.println(Thread.currentThread().getId()+",值:" + testMyLock.getValue());
              }
            };
    
            new Thread(runnable).start();
            new Thread(runnable).start();
            new Thread(runnable).start();
            
            //检测重入锁
            Runnable runnable1 = () -> testMyLock.a();
            new Thread(runnable1).start();
        }
    }
  • 相关阅读:
    Json字串转换成Java复杂对象
    [Code Snipper]图片轮换
    将CSDN600W用户及密码帐号存入本地MySql数据库
    【转】一个隐形的java int溢出
    【转】展望未来,总结过去10年的程序员生涯,给程序员小弟弟小妹妹们的一些总结性忠告
    如何在Android 4.0 ICS中禁用StatusBar | SystemBar | 状态栏 【完美版】
    【转】提问的智慧(How To Ask Questions the Smart)
    商业开发实战之VB篇精彩视频
    我的设计原语
    RAPIDXML 中文手册,根据官方文档完整翻译!
  • 原文地址:https://www.cnblogs.com/gyli20170901/p/10905055.html
Copyright © 2011-2022 走看看