天天看点

Java并发编程艺术笔记

第二章 Java 并发机制的底层实现原理

1.volatile是轻量级的sychronized,保证了共享变量的可见性。可见性的意思是当一个线程修改一个共享变量的时候,另外一个线程能读到这个修改的值。

volatile instance = new Singleton()

转成汇编代码,如下

0x01a3de1d: movb 0x0,0x1104800( 0x0, (%)

2.Java 语言规范第三版对volatile的定义如下:Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁��单独获得这个变量。

3.volatile 的两条实现原则

1)Lock前缀指令会引起处理器缓存回写到内存。

2)一个处理器的缓存回写到内存会导致其它处理器的缓存无效

3)volatile的使用优化,Java并发编程大师Doug lea的JDK7的并发包里新增一个队列集合类LinkedTransferQueue,它在使用volatile变量时,用一种追加字节的方式来优化队列处队和入队的性能。Doug lea使用追加64字节的方式来填满告诉缓冲区的缓存行,避免头尾节点加载到同一个缓存行,使2个节点的修改不会互相锁定。

4.sychronized的实现原理与应用

1)重量级锁,Java SE1.6为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁,以及锁的存储结构和升级过程。

2)JVM基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不一样。代码块同步是使用monitorenter和monitorexit指令实现的,而方法同步则是使用另外一种方式实现的。

5.锁的升级与对比

HotSpot的作者经过研究发现,大多数情况下,锁不仅不存在多线程竞争,而且总是由同一个线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。

轻量级锁使用CAS自旋来获取锁。

重量级锁,线程阻塞来竞争锁。

第三章 Java内存模型

JVM的逻辑内存模型

Java并发编程艺术笔记

1)程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看

做是当前线程所执行的字节码的行号指示器,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储。

Happens-before是JMM最核心的概念。

第四章 Java并发编程基础

1.线程优先级不能作为程序正确性的依赖,因为操作系统可以完全不用理会java对于线程优先级的设置。

2.中断可以理解为线程的一个标识位属性,它表示一个运行中的线程是否被其它线程进行了中断操作。中断好比其它线程对该线程打了个招呼,其它线程通过该线程的interrupt()方法对其进行中断操作。isInterrupted()可以用来进行判断是否被中断,也可以调用静态方法Thread.interrupted()对当前线程的中断标识位进行复位。mark:如果该线程处于终结状态,即使该线程被中断过,isInterrupted()依然返回false。

3.volatile保证线程的可见性,sychronized保证线程的可见性及排它性。

4.管道输入/输出流,它主要用于线程之间的数据传输,而传输的媒介为内在。

第五章 Java中的锁

1.Lock接口与sychronized的不同,失去了隐式获取与释放锁的便利,却拥有了获取与释放锁的灵活性,可操作性,可中断及超时的获取锁。

2.队列同步器AbstractQueuedSychronizer,是用来构建锁或者其它同步组件的基础框架

1)使用int成员变量表示同步状态

2)通过内置的FIFO队列来完成资源获取线程的排队工作

3)使用方式是继承,实现其抽象方法来管理同步状态,通过getState,setState,compareAndSetState原子性的改变同步状态

4)子类被推荐作为自定义同步组件的静态内部类,同步器本身不实现任何同步接口,仅仅定义了若干同步状态获取和释放的方法来供自定义同步组件使用

3.同步器是锁实现的关键,在锁的实现中聚合同步器,利用同步器来实现锁的语义。可以这样理解二者的关系:锁是面向使用者的,它定义了使用者与锁交互的接口,隐藏了实现细节,同步器面向的是锁实现者,它简化了锁的实现方式,屏蔽了同步状态管理,线程排队,等待与唤醒等底层操作。锁和同步器很好的隔离了使用者和实现者所需要关注的领域。

4.同步器的设计是基于模板方法模式的,也就是说,使用者需要继承同步器并重写指定的方法。

5.队列同步器的实现分析

1)同步队列,一个FIFO双向队列,当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成一个节点Node并将其加入同步队列,同时阻塞当前线程,当同步状态释放时,会把首节点中的线程唤醒,使其再次尝试获取同步状态

2)Node:

Java并发编程艺术笔记

waitStatus:等待状态,

CANCELLED:1(由于在同步队列中等待的线程等待超时或者被中断),需要从同步队列中取消等待,节点进入该状态将不会变化

SIGNAL:值为-1,后继节点的线程处于等待状态,而当前节点的线程如果释放了同步状态或者被取消,将会通知后继节点,使后继节点的线程得以运行

CONDITION:值为-2,节点在等待队列中,节点等待在Condition上,当其它线程对Condition调用了signal()方法后,该节点将会从等待队列中转移到同步队列中,加入到对同步状态获取中

PROPAGATE:值为-3,表示下一次共享式同步状态将会无条件地被传播下去

prev:前驱节点,当节点加入同步队列时被设置(尾部添加)

next:后继节点

nextWaiter:等待队列中的后继节点。如果当前节点是共享的,那么这个字段将是一个SHARED常量,也就是说节点类型(独占与共享)和等待队列中的后继节点共用同一个字段

6.重入锁,支持重进入的锁,表示该锁能够支持一个线程对资源的重复加锁,另外可支持公平与非公平2种选择,另外sychronized隐匿支持重进入

1)实现可重入

线程再次获取锁:锁需要去识别获取锁的线程是否为当前持有锁的线程,如果是,则再次成功获取;

锁的最终释放:线程N次获取锁,随后在第N次释放了锁,其它线程能够获取到锁,锁的最终释放需要锁对于获取进行自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数为0时表示锁被成功释放

非公平锁可以减少线程的切换

7.读写锁

1)读写锁的实现分析

读写状态的设计:一个整型变量,高16位表示读,低16位表示写,假设当前状态为S,写状态等于S&0x0000FFFF(将高16位抹去),读状态等于S>>>16(无符号右移16位)

写状态+1:S+1

读状态+1:S+(1<<16),也就是S+0x00010000

2)锁降级:写锁降级为读锁,把持住写锁,再获取读锁,随后释放写锁

8.LockSupport工具,阻塞与唤醒线程

9.Condition类似Object监视器

Java并发编程艺术笔记