java并发-重入锁(ReentrantLock)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_22271479/article/details/85035196

重入锁(ReentrantLock)

含义

重入锁,标识在一个线程中,可重复对该资源重复加锁。

  • synchronized就是重入锁
  • ReentrantLock也支持冲入操作
  • 是排它锁(独占锁)

针对于AQS实现重入功能
在重写tryAquiresxxx的时候考虑同一个线程多次lock的情况即可

伪代码

  • aquire方法
        Thread currentThread = Thread.currentThread();
        //getExclusiveOwnerThread() 标识独占模式下的当前线程对象引用
        if(currentThread == getExclusiveOwnerThread())
  • release方法
    • 这里,就是当前线程获取了多次
    • 比如1.lock() 2.lock() 3.unlock() 4.unlock
    • 这里ReentrantLock的aquire()方法传入的是1
    • 执行1,2后state分别是 1,2
    • 执行3 c = 2-1 //setState(2-1)
    • 执行4 c = 1-1 //直接释放
    protected final boolean tryRelease(int releases) {
                //同一个线程多次获取资源锁的话,state会累加,那么这里做累减操作
                int c = getState() - releases;
                //不是当前线程去release的话,抛出monitor异常,当然并不是monitor底层实现的
                if (Thread.currentThread() != getExclusiveOwnerThread())
                    throw new IllegalMonitorStateException();
                boolean free = false;
                //c == 0的话,就表示不存在一个线程获取多次,那么直接release
                if (c == 0) {
                    free = true;
                    setExclusiveOwnerThread(null);
                }
                //这里,就是当前线程获取了多次
                //比如1.lock() 2.lock() 3.unlock() 4.unlock
                //这里ReentrantLock的aquire()方法传入的是1
                //执行1,2后state分别是 1,2
                //执行3  c = 2-1 //setState(2-1)
                //执行4  c = 1-1 //直接释放
                setState(c);
                return free;
            }

公平锁和非公平锁

  • AQS 默认没有处理锁的公平争夺策略,获取锁的逻辑是需要用户自行定义
  • ReentrantLock实现了公平和非公平
  • 多线程下,线程去获取锁的顺序是不固定的
  • 公平锁比非公平锁性能要低(需要拒绝获取,直到该线程是head的时候才会成功获得资源锁)

Node链表 head–>N1(pre,next)–>N2(pre,next)<–tail

    
    //true 标识在队列中的该线程拥有前置节点
    //false 该线程是head或者 null==null即空队列 tail==head==null
      
    public final boolean hasQueuedPredecessors() {
               Node t = tail; // Read fields in reverse initialization order
               Node h = head;
               Node s;
               return h != t &&
                   ((s = h.next) == null || s.thread != Thread.currentThread());
    }
    
    protected final boolean tryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                if (c == 0) {
                //非公平锁  没有hasQueuedPredecessors()方法
                    if (!hasQueuedPredecessors() &&
                        compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
                else if (current == getExclusiveOwnerThread()) {
                    int nextc = c + acquires;
                    if (nextc < 0)
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
                }
                return false;
    }

公平锁最终获得锁的顺序和队列中的顺序是一致的,FIFO

公平与非公平性能

  • 公平锁能保证FIFO规则,但是增加了线程切换的次数

为什么?

AQS操作虽然使用CAS无锁操作机制,但是,CPU在调度的时候,切换至该线程的时候,该线程去获取该资源锁,但是FIFO原则,无法获取锁,将处于自旋操作,后续线程任务无法执行,cpu调度结束,就切换至下一个线程。

公平锁大大的增加了CPU线程调度次数,导致吞吐率(TPS)降低

  • 非公平锁,只要该线程获得到CPU时间片,那么在没有线程获取锁的时候,就可以得到锁,执行任务,减少了线程切换,提高了TPS。

使用

/**
 * describe:
 * E-mail:[email protected]  date:2018/12/16
 *
 * @Since 0.0.1
 */
public class ReentRantLockTest {

    //默认构造是非公平
    //true是公平锁
    //false是非公平锁
    public static final Lock lock = new ReentrantLock(true);

    static class T extends Thread {
        public T(String name){
            super(name);
        }
        @Override
        public void run() {
            lock.lock();
            System.out.println("==" + Thread.currentThread().getName());
            try {
                //Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            test.T t = new test.T(String.valueOf(i+"Thread"));
            t.start();
        }
        System.out.println(null == null);
    }
}

不公平锁
在这里插入图片描述

公平锁
在这里插入图片描述

GitHub主页

猜你喜欢

转载自blog.csdn.net/qq_22271479/article/details/85035196