《Java并发编程实战》学习笔记

Posted __Meng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Java并发编程实战》学习笔记相关的知识,希望对你有一定的参考价值。

 

二、线程安全性

 

正确性:

  某个类的行为与其规范完全一致。

 

线程安全:

  当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类就能表现出正确的行为,那么就称这个类是线程安全的。

 

无状态对象

  既不包含任何域,也不包含任何其他类中域的引用的对象。

  无状态对象一定是线程安全的。

 

竞态条件:

  当某个计算的正确性取决于多个线程的交替执行时序时,就会发生竞态条件。

  本质是基于一种可能失效的观察结果来做出判断或者执行某个计算。

  最常见的竞态条件类型就是“先检查后执行(Check-then-Act)”。

  “读取-修改-写入”操作也是一种竞态条件。

 

原子性:

  假定有两个操作A和B,如果从执行A的线程来看,当另一个线程执行B时,要么将B全部执行完,要么完全不执行B,那么A和B对彼此来说是原子的。

 

原子操作:

  对于访问同一个状态的所有操作(包括操作本身)来说,这个操作是一个以原子方式执行的操作。

  要保持状态的一致性,就需要在单个原子操作中更新所有相关的状态变量。

 

内置锁:

  每个Java对象都可以用作一个实现同步的锁,这些锁被称为内置锁(Intrinsic Lock)或者监视器锁(Monitor Lock)。

  内置锁是一种互斥锁,最多只有一个线程持有这个锁。

 

同步代码块(Synchronized Block)包括两部分:

  一个作为锁的对象引用,一个作为由这个锁保护的代码块。

  关键字Synchronized修饰方法就是一种同步代码块,锁就是方法调用所在的对象,静态的Synchronized方法以Class对象作为锁。

 

重入

  因为内置锁是可重入的,所以如果某个线程试图获得一个已经由它自己持有的锁,那么这个请求就会成功。

  重入意味着获取锁的操作粒度是“线程”,而不是“调用”。

  实现方式:为每个锁关联一个获取计数值和一个所有者线程。当计数值为0时,这个锁被认为没有被任何线程持有。当线程请求一个未被持有的锁时,JVM将记下锁的持有者,并且将获取计数值置为1。如果同一个线程再次获取这个锁,计数值将递增,而当线程退出同步代码块时,计数值减1。

  重入提升了加锁行为的封装性,因此简化了面向对象并发代码的执行。

 

用锁来保护状态:

  锁能够使其被保护的对象以串行方式来执行。

  对于可能被多个线程同时访问的可变状态变量,在访问它时都需要持有同一个锁,在这种情况下,我们称状态变量是由这个锁保护的。 

  对象的内置锁与其状态之间没有内在的联系,虽然大多数类都将内置锁用做一种有效的加锁机制,但对象的域并不一定要通过内置锁来保护

  一种常见的加锁约定:将所有可变状态都封装在对象内部,并通过对象的内置锁对所有访问可变状态的代码路径进行同步,使得该对象上不会发生并发访问。

  对于每个包含多个变量的不变性条件,其中涉及的所有变量都需要由同一个锁来保护。

 

活跃性与性能:

  将同步代码块分解得过细并不好,因为获取与释放锁操作需要开销。

  当执行时间较长的计算或者可能无法快速完成的操作时(如I/O),一定不要持有锁。

  同时使用两种不同的同步机制会带来混乱,在性能或安全性上也没有任何好处。(如内置锁synchronized和Atomic原子变量) 。

 

以上是关于《Java并发编程实战》学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

Java并发编程实战读书笔记之死锁

《java并发编程实战》笔记

《C++ 并发编程实战 第二版》学习笔记目录

《C++ 并发编程实战 第二版》学习笔记目录

《Java并发编程实战》读书笔记

《Java并发编程实战》读书笔记