java进阶-7-D -多线程-Lock专题- ReentrantLock类

java进阶-7-D -多线程-Lock专题- ReentrantLock类

开篇一张,故事全靠~~~:根据AQS来自己实现一个Lock吧

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @author Shengwuyou
 * @data 2019/3/1 0001 14:35
 */
public class SelfLock implements Lock {

    private static Sync sync = new Sync();

    private static class Sync extends AbstractQueuedSynchronizer{
        /**
         * 判断当前线程是否是独占式获取锁
         * @return
         */
        @Override
        protected boolean isHeldExclusively() {
            //判断当前运行的线程 和 占据着锁的线程是否一致 下面的代码
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        /**
         * 尝试获取锁的判断逻辑也是非常简单,判断当前Lock的状态state  n = 0表示还没有线程占用锁, n=1表示有一个线程占用了 ,当 n大于1的时候表示该锁 重入了n次
         * 这里对于重入可多少个锁互相竞争锁是没有关系的,重入例子 ==> Lock{  Lock{}finally{unlock}  }finally{unlock}  此时n=2
         * @param arg
         * @return
         */

        @Override
        protected boolean tryAcquire(int arg) {
            int state = getState();
            if (state == 0){
                if (compareAndSetState(state,arg)) {
                    setExclusiveOwnerThread(Thread.currentThread());
                    return true;
                }
            } else if (state > 0 && isHeldExclusively()){
                if (compareAndSetState(state,state+arg)) {
                    return true;
                }
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            int expState = getState() - arg;
            if (isHeldExclusively()){
                throw new IllegalThreadStateException();
            }else if (expState == 0 ){
                setExclusiveOwnerThread(null);
            }
            setState(expState);
            return true;
        }

        public Condition newCOndition(){
            return new ConditionObject();
        }
    }

    @Override
    public void lock() {
        sync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1,time);
    }

    @Override
    public void unlock() {
        sync.release(1);
    }

    @Override
    public Condition newCondition() {
        return sync.newCOndition();
    }
}

一眼看下来其实非常简单!就tryAcquire 和 tryRelease 这2个方法,而且里面要做的就是去修改一个参数state                            锁的状态:我们在自定义锁的时候定义这个state的规则:0表示锁未被任何线程占用 ,>0 表示被某一个线程占用了,设定 步长是1,表示占用的线程每重入一次state就加一。

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author Shengwuyou
 * @data 2019/3/1 0001 15:31
 */
public class SelfLockTest {
    public static void main(String[] args) {
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3,5,60,
                TimeUnit.SECONDS,new LinkedBlockingQueue<>(30), new ThreadPoolExecutor.DiscardOldestPolicy());

        SelfLock lock = new SelfLock();

        Runnable run = ()->{
          lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " : --- 休眠3秒");
                Thread.sleep(3000);
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " : ---重入再次 休眠3秒");
                    Thread.sleep(3000);
                } finally {
                    lock.unlock();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        };

        for (int i = 0;i <10; i++){
            poolExecutor.execute(run);
        }
        poolExecutor.shutdown();
    }
}

测试的结果喜人,这里我没有将state的变化打印出来但是有兴趣的小伙伴可以加到selfLock中,或者debug查看

 

从fairSync  和 nonfairSync ---开始介绍ReentrantLock:

对于公平 / 非公平 获取锁 ,区别点就是                                                                                                                                          公平锁:新任务进来必须加入到等待队列之后让等的最久的那个任务先执行                                                                            非公平锁 :新任务进来先去尝试能够获取到锁,不行在加入到等待队列的尾巴上。   

在我们分析之后非公平锁是会比公平锁在性能上有优势,但是碰到执行任务的时间花费很长的情况,2种锁的差距会缩小到可以忽略,但是公平锁能够保证任务的先进先出,这个优势是很多地方需要用到的

非公平锁和公平锁的代码实现区别就一点 :在 Lock的时候

NonFair 会在当前没有线程占有锁的时候    直接去判断能够拿到锁,能得话就over  --------上面的例子是非公平锁

Fair       会在当前没有线程占有锁的时候     判断一下等待队列中是否有Node,有的话那就加入到等待队列尾部

代码差异也是非常简单这里就不讲了