并发编程实战-第二章学习

“共享”意味着变量可以由多个线程同时访问,而“可变”则意味着变量的值再其声明周期内可以发生变化。

如果当多个线程访问同一个可变的状态变量时没有使用合适的同步,那么程序就会出现错误,有三种方式可以修复这个问题:

  • 不在线程之间共享该状态变量(有点扯,既然我要共享一个状态变量,怎么可能不共享,只能说不共享肯定不会涉及状态的同步)
  • 将状态变量修改为不可变的变量。
  • 在访问状态变量时使用同步

什么是线程安全性

线程安全性的核心是正确性,即当多个线程访问某个类时,这个类使用都能变现出正确的行为,那么这个类就是线程安全的。

在线程安全性一章中给出的定义:

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

无状态对象一定是线程安全的,无状态即不包括任何域、也不包括任何对其他类中的域的引用。

 

原子性

原子操作是指,对于访问同一个状态的所有操作(包括该操作本身)来说,这个操作是一个原子的操作。(个人理解:所谓的原子,即最小单位,不可再分割,对于操作来说,及时是复合操作,同样通过加锁等其他方式将其捆绑在一起完成)

该节提出了产生数据不一致的问题,从而引出了,“先检查后执行”的操作,即通过一个可能失效的观察结果来决定下一步的动作。通过举例了两个朋友相约咖啡厅的故事进行了描述,通俗易懂,其中我个人认为比较重要的一句----“当你迈出前门时,你在星巴克A的观察结果将变得无效,因为他可能已经从后门进入了星巴克,只是你不知道而已”。、

通过long的couut操作说明了符合操作,++count,涉及的操作为读取-修改-写入三部分操作,通过使用java.util.concurrent.atmoic包中的原子变量类AtomicLong来代替long类型来解决该问题是其成为一个线程安全的操作。

在实际情况中,应尽可能地使用现有的线程安全对象(例如AtomicLong)来管理类的状态,与非线程安全的对象相比,判断线程安全对象的可能状态及其状态转换情况要更为容器,
从而更容易维护和验证线程安全性

 加锁机制

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

重入意味着获取锁的操作的粒度是线程,而不是调用。重入的一种实现方法是,为每个锁关联一个获取计数值和一个所有者线程。

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

需要注意的一点是即使是同步方法的符合操作,同样会导致竞态条件问题。如下代码,虽然vector是的每个方法是原子方法,但是复合操作,同样会导致出现数据不一致问题。

1 if ( !vector.contains(element))
2     vector.add(element)

 

遗留问题

1、原子性小节同样提到了单例的实现,该问题需要统一整理所有单例的实现方法,记一个遗留问题,下周解决

已经复习了单例的相关知识,见:http://www.cnblogs.com/woniu4/p/8287484.html

 

posted @ 2018-01-14 21:48  woniu4  阅读(142)  评论(0编辑  收藏  举报