java-线程-锁

ReentrantLock vs synchronized

  • 相同点
    • 可重入
    • 互斥锁
    • 隐性monitor:对synchronized是利用object对象头实现监控操作; 而对于Lock利用newCondition提供的Condition实现
      • 对于monitor的作用主要是为了实现线程通讯
  • 不同点
    • 支持fair 和 unfair 方式来获取竞态条件
    • 限时获取(tryLock(long,TimeUnit))
    • 条件对象(Condition)支持,并且提供了丰富的api
    • 运维方法

 重进入

 public static void getReentrantTime() {
        ReentrantLock reentrantLock = new ReentrantLock();
        reentrant(reentrantLock, 10);
    }

    public static void reentrant(ReentrantLock reentrantLock, int times) {
        if (times <= 0) {
            return;
        }
        if (reentrantLock.tryLock()) {
            try {
                reentrant(reentrantLock, --times);
                log.info("第{}次当前线程对当前锁进入次数为:{}", times + 1, reentrantLock.getHoldCount());
            } finally {
                reentrantLock.unlock();
            }
        }
    }

condition

 /**
     * 通过condition实现线程通讯
     */
    public static void condition() {
        ReentrantLock reentrantLock = new ReentrantLock();
        Condition condition = reentrantLock.newCondition();
        new Thread(() -> {
            while (true) {
                if (reentrantLock.tryLock()) {
                    try {
                        int waitQueueLength = reentrantLock.getWaitQueueLength(condition);
                        log.info("当前等待线程数量为:{}", waitQueueLength);
                        if (waitQueueLength > 10) {
                            condition.signalAll();
                        }
                    } finally {
                        reentrantLock.unlock();
                    }
                }
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        while (true) {
            new Thread(() -> {
                if (reentrantLock.tryLock()) {
                    log.info("当前线程id:{}", Thread.currentThread().getId());
                    try {
                        condition.await();
                        log.info("当前线程被唤醒:{}", Thread.currentThread().getId());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        reentrantLock.unlock();
                    }
                }
            }).start();
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

synchronized和ReentrantLock对比

  public static void synchronizedVsTryLock() {
        // 对于这种情况存在死锁的可能性,更多的可能性为线程饥饿,无法控制获取锁的等待时间
        synchronized (ReentrantLockDemo.class) {

        }
        ReentrantLock reentrantLock = new ReentrantLock();
        try {
            // 可以通过使用tryLock控制获取锁的等待时间
            // 对于tryLock方法只有在获取锁成功后才会返回true,获取锁失败则会返回false
            if (reentrantLock.tryLock(10, TimeUnit.SECONDS)) {

            }
        } catch (InterruptedException e) {
            // 由于在等待获取锁的过程中,线程有可能已经中止,因此会抛出线程中止异常
            e.printStackTrace();
            // 由于在AQS判断中当前线程已被中止,但其结果存在一些运算操作因此为了保证当前线程不会再继续执行,则手动终止当前线程
            Thread.currentThread().interrupt();
        }
    }

 

对于公平锁和非公平锁的个人理解

由于线程调度的原因,每个线程真正执行的时间点是不可控的,因此在并发情况下对于CPU线程调度是乱序的,为了保证公平性,因此通过AQS队列中的等待者来判断保证获取的线程也是按照等待队列的顺序进行执行按照FIFO     

posted @ 2020-09-26 21:16  郭星  阅读(155)  评论(0)    收藏  举报