知识点(第五、六、七章)
1、Lock接口
关键点:(1)lock和synchronized的区别,后者是通过monitor+对象头的方式控制线程的同步,锁的获取和释放都是隐式完成的,而lock则是手把手的获取与释放锁;(2)lock可以尝试非阻塞的获取锁,以及超时获取锁,并且,与synchronized不同,获取到锁的线程能够响应中断,同时释放锁。
2、AQS
这个是重中之重!!这个部分在第一次看完的时候感觉完全没懂,后面慢慢的通过阅读源码以及实现其子类的源码才慢慢了解,同步器在我们的日常开发中并没有被直接使用到,它是一个负责构建锁或者其他同步组件的基础框架,这时书上的原话,翻译过来就是,实现实现锁的基础框架,封装了同步状态管理、线程排队以及等待唤醒等底层操作,主要包括一下几个知识点:
state:一个全局的int型变量表示同步状态,当需要更改同步状态时,则通过getState、setState以及compareAndSetState来进行操作以保证状态改变的安全性;
acquire:独占式获取同步状态,成功则返回,失败则进入同步队列等待(独占锁的获取实现,如写锁);
acquireInterruptibly:顾名思义,可以响应中断的acquire方法;
tryAcquireNanos:在acquireInterruptibly的基础上增加了超时限制;
acquireShare:共享式的获取同步状态,与独占式的区别在于同一时刻可以有多个线程同时获取到同步状态(共享锁的获取实现,如读锁);
- acquireShareInterruptibly:响应中断;
- tryAcquireShareNanos:增加超时;
- release:独占式的释放同步状态,在释放同步状态后,将同步队列中的第一个节点包含的线程唤醒;
- releaseShare:共享式的释放同步状态;
实现原理:
同步队列:同步器依赖内部的一个FIFO同步队列来完成同步队列的管理,当获取同步状态失败时,会将该线程构造成一个Node节点并将其加入同步队列,同时阻塞当前线程。注意:设置尾节点时是CAS操作,因为可能由于多个线程获取同步状态失败而加入到尾节点,而设置头结点则不需要,因为只有一个线程可以成功获取同步状态;
同步状态的获取与释放:包括独占式以及共享式同步状态的获取与释放,一定要看这块的源码;
3、重入锁
重入锁的定义即支持重入,支持一个线程对资源反复加锁,在释放的时候,也需要将锁全部释放才算完全释放。ReentrantLock使用syn变量控制重入锁来控制锁的策略,包括公平与非公平两种(默认非公平),公平锁即每次都是等待队列中的第一个节点获得锁,缺点是吞吐量会下降(由于线程的大量切换),非公平锁则不是按照FIFO规则来,比如第一个请求不成功,则会切换到第二个节点请求锁,这样能够提高吞吐量,缺点就是可能会造成饥饿。
4、读写锁
读写锁即读锁和写锁,通过减小锁的粒度提高并发性能;读操作时获取读锁,写操作时获取写锁,当线程获取到写锁时,后续的读写操作都会被阻塞,当写锁释放之后,其余的操作才能继续执行,jdk提供的ReentrantReadWriteLock包括以下特性:公平性选择、重进入以及锁降级;这里值得一提的是锁降级,遵循获取写锁、获取读锁再释放写锁的次序,将写锁降级为读锁,这里的读锁是在写锁获取之前获取的,比如线程A获取写锁修改数据,此时如果没有获取读锁就释放了写锁,正好这时候线程B获取了写锁修改了数据,那么线程A就完全感知不到数据的变化,而提前获取读锁则能阻塞线程B获得写锁,这样保证读数据的正确性;其同步状态是通过一个32位的变量控制,高16位为读状态,低16位为写状态。
5、常用的并发容器
ConcurrentHashMap:略
ConcurrentLinkedQueue:使用HOPS常量控制tail节点的更新,只有距离大于hops才需要使用CAS更新tail节点;
阻塞队列:ArrayBlockingQueue, LinkedBlockingQueue, PriorityBlockingQueue, DelayQueue, SynchronousQueue, LinkedTransferQueue, LinkedBlockingDequeue;实现原理:通知者模式,通过Condition来实现put和take时的阻塞等待;
6、Fork/Join
关键点:工作窃取算法,即某个线程从其他队列里窃取任务来执行,这样可以充分利用线程进行并行计算,减少线程间的竞争,类似MapReduce(我是这么理解的),包括fork(分割任务)和join(执行任务合并结果)的过程。
实现原理:
fork:调用ForkJoinWorkerThread的pushTak方法异步的执行任务,然后立即返回结果,将当前任务存放在ForkJoinTask数组队列中,然后调用signalWork方法唤醒或创建一个工作线程来执行任务;
Join:用四种状态值来判断doJoin方法是否完成;
7、13种原子操作类
AtomicBoolean:原子更新布尔类型,其本质也是先转整形;
AtomicInteger:原子更新整形;
AtomicLong:原子更新长整形;
AtomicIntegerArray:原子更新数组整形数组里的元素;
AtomicLongArray:原子更新长整形数组里的元素;
AtomicReferenceArray:原子更新引用类型数组里的元素;(这里需要指出185页的一个错误,addAndGet方法应该是以原子方式将索引位置的元素更新为输入值);
AtomicReference:原子更新引用类型;
AtomicReferenceFieldUpdater:原子更新引用类型里的字段;
AtomicMarkableReference:原子更新带有标记位的引用类型(可以原子更新对象);
AtomicIntegerFieldUpdater:原子更新整形的字段;
AtomicLongFieldUpdater:原子更新长整形字段的更新器;
AtomicStampedReference:原子更新带有版本号的引用类型(可以解决ABA问题);