Java并发编程的艺术笔记(五)

5. java中的锁

1. Lock接口

Lock接口是在Java SE 5 出现的,Lock接口比Synchronized更为灵活,增加了中断、超时等功能。但是失去了synchronized隐式解锁的方便性,需要手动解锁,因此Lock更容易造成死锁条件。

Lock扩展性更强、synchronized更为便捷。

Lock依赖于底层的同步器实现,也就是前文说到的AQS。

2. 队列同步器

AbstractQueueSynchronized,队列同步器。用来构建锁的或者其他同步组件的基本框架,用过int表示同步状态,通过队列完成资源获取的排队工作。同步器主要是继承用的,为开发者扩展设计的,比如ReentrantLock、ReentrantWriteLock、CountDownLatch。

简化了锁的实现方式,屏蔽了同步状态管理、线程队列、等待和唤醒等底层操作。

队列同步器是基于模板方法模式的,使用者需要继承同步器来重写里面的方法

访问或者修改状态的三种方法:

  • getState:获得当前同步状态
  • setState:设置当前同步状态
  • compareAndSetState:使用CAS设置当前状态,方法能够保证状态的原子性

同步队列

同步器依赖于内部的同步队列,如果当前线程获得同步状态失败,同步器会将当前线程以及等待状态等信息构造成一个节点,加入到同步队列中,并阻塞当前线程。当同步状态释放时,会把节点中的线程唤醒。

在这里插入图片描述

下图是独占锁执行过程

在这里插入图片描述

3. 重入锁

重入锁是指任意线程获得锁之后,能够再次获得此锁而不被阻塞

该特性的实现有两个问题:

  • 线程获得锁而不被阻塞

  • 锁的最终释放

    锁需要识别当前线程是否为占据锁的线程,如果是则再次获取。

    锁的释放是通过计数器来实现的,当计数器减到0时,表示锁已经成功释放。

4. 读写锁*

5. LockSupport工具

LockSupport类中定义了一组公共静态方法,提供了最基本的线程阻塞、线程唤醒。


import java.util.concurrent.locks.LockSupport;

public class LockSupportDemo {

    public static void main(String[] args) {
        for (int i=0 ; i<5 ; i++){
            Thread thread = new Thread(new Runnable() {
                            @Override
                            public void run() {
                                int time = (int)(Math.random()*100) ;
                                LockSupport.parkNanos(time);
//                                LockSupport.park();
                                System.out.println(Thread.currentThread().getName()+"  "+time );
                            }
                        }, "thread-" + i) ;
            thread.start();
            LockSupport.unpark(thread);
        }

    }

}

6. Condition接口

synchronized关键字和wait()、notify()、notifyAll()配合。

而Condition就是和Lock进行配合的。

Condition是由lock.newCondition()创建的。

  • await == wait
  • signal == notify
  • signalAll == notifyAll
    public Condition newCondition() {
        return sync.newCondition();
    }
		final ConditionObject newCondition() {
            return new ConditionObject();
        }

ConditionObject是由AbstractQueueSynchronizer类的内部类,底层是使用的是LockSupport。

原因是 Condition的操作是要获取锁,所以作为AQS类的内部类是最合适的。

  • 同步队列:获取同步状态失败的线程会进入到同步队列,同时会阻塞该线程,当同步状态释放后,会把首节点的线程唤醒,再次尝试获取同步状态。
  • 等待队列:等待队列中的线程就是在Condition对象上等待的线程。

一个Condition包含一个等待队列。

  • signal方法:唤醒等待队列中等待时间最长的结点(首节点),在唤醒节点之前,将节点移动到同步队列中。
  • signalAll方法:相当于对等待队列中的所有结点都做一遍signal,效果就是将等待队列中的所有节点都转移动同步队列中,并唤醒这些线程。

在这里插入图片描述

  • await:调用该方法的线程一定是获得此锁的线程,也就是同步队列的头节点,该方法会当前线程加入到等待队列,释放同步状态,并且唤醒后继结点。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值