《程序员修炼之道》-读书笔记五-现代并发
第四章 现代并发
4.2.1 同步与锁
-
只能锁定对象,不能锁定基本类型
个人理解,加锁时,锁需要类似sumCount的计数器机制来加锁和释放锁,而这些东西是Object类才拥有的,基本类型没有,这也就是说,为什么锁只能是引用类型的,而不能是基本类型.
- 被锁定的对象数组中的单个对象不会被锁定.
- 同步方法可以视同为包含整个方法的同步(this) { ... }代码块(但要注意他们的二进制码表示是不同的)
- 静态同步方法会锁定它的Class对象,因为没有实例对象可以锁定
- 如果要锁定一个类对象,请慎重考虑是用显式锁定,还是getClass(),两种方式对子类的影响不同.
- 内部类的同步是独立于外部类的(要明白内部类是如何实现的)
- synchronized不是方法签名的组成部分,所以不能出现在接口方法声明中
- 非同步的方法不查看或关心任何锁的状态,而且在同步方法运行时他们仍能继续运行.
- Java的线程锁是可重入的.也就是说持有锁的线程在遇到同一个锁的同步点(比如一个同步方法调用同一个类内的另一个同步方法)时,是可以继续的
Java中的synchronized和ReentrantLock都是可重入锁。所以如果需要使用不可重入锁,则需要自己实现了。
4.2.3 完全同步对象
如果一个类遵从下面所有规则,就可以认为他是线程安全并且活跃的.
- 所有域在任何构造方法中的初始化都能达到一致的状态
- 没有公共域
- 从任何非私有方法返回后都可以保证对象实例处于一致的转态(假定调用方法时状态是一致的).
- 所有方法经证明都可在有限时间内终止.
- 所有方法都是同步的.
- 当处于非一致状态时,不会调用其他实例的方法.
- 当处于非一致状态时,不会调用非私有方法.
4.2.5 为什么是synchronized?
这是之前作者让思考的一个问题,Java中用于确立临界区的关键字为什么是synchronized(同步的)?为什么不是"critical(临界的)"或"locked(上锁的)"?同步的是什么?
首先来说被同步的是什么?答案是:被同步的是在不同线程中表示被锁定对象的内存块.也就是说,在synchronized代码块(或方法)执行完之后,对被锁定对象所做的任何修改全部会在线程锁释放之前刷会到主内存中.如图所示
另外,当进入一个同步的代码块,得到线程锁之后,对被锁定对象的任何修改都是从主内存中读取出来的,所以在锁定区域代码开始执行之前,持有锁的线程就和锁定对象主内存中的视图同步了.
4.2.6 关键字volatile
一个volatile域需要遵循如下规则:
1.线程所见的值在使用之前总会从主内存中再读出来.
2.线程所写的值总会在指令完成之前被刷回到主内存中.
volatile变量是真正线程安全的,但只有写入时不依赖当前状态(读取的状态)的变量才应该声明为volatile变量.(当变量的值由自身的上一个值决定时,如n=n+1、n++ 等,volatile关键字将失效,只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的).
对于要关注当前状态的变量,只能借助线程锁保证其绝对安全性.