第四章:并发之共享模型
共享带来的问题
为什么需要共享cpu
无法利用cpu的情况:sleep,wait,io操作,通过分时系统提交cpu的利用率。即一个时间段内多个线程可以获取cpu资源
java中的体现
问题的产生:线程一对静态变量i自加5000次,线程二对静态变量i自减5000次,最后的i不是0.
问题分析:i++操作在字节码层面不是一条指令。分为多条指令进行,在运算时在线程内进行运算然后写到主存,所线程一中计算后的结果还没有写到主存中cpu时间片用完了,线程二读取到了未被计算的i,所以造成这个结果
[图片上传失败...(image-f598a4-1606228386315)]
临界区
[图片上传失败...(image-524999-1606228386315)]
一段代码块内如果存在对共享资源的多线程读写操作,这段代码块称为临界区
竞太条件
多个线程在临界区内执行,由于代码的执行序列不同导致结果无法预测,称之发生了竞态条件
解决方法
阻塞式:synchronized,lock
非阻塞式:原子变量
[图片上传失败...(image-a04da6-1606228386315)]
互斥是对于同一资源来说的(静态变量i),同步只是规定了线程的执行顺序
synchronized保证了操作的原子性,但并不保证可见性???
synchronized
在修改了本地内存中的变量后,解锁前会将本地内存修改的内容刷新到主内存中,确保了共享变量的值是最新的,也就保证了可见性。
[图片上传失败...(image-43fc39-1606228386315)]
方法上的synchronized
[图片上传失败...(image-436c77-1606228386315)]
变量线程安全分析
方法本身是线程私有的,安不安全是对于这个方法里操作的资源来说的,如果这个资源是静态变量或者是引用对象等有可能造成线程不安全的问题
成员变量的安全性
[图片上传失败...(image-17d338-1606228386315)]
局部变量的安全性
子类继承造成的线程安全问题
当子类覆盖了父类的方法后父类的局部变量会暴漏,方法的访问修饰符是有意义的,可以在一定程度上保护方法中的资源安全问题
常见线程类
String,Integer,StringBuffer,Random,HashTable,concurrent包下的类。
也就是说他们的每个方法是原子的,==但是组合在一起不一定是线程安全的==
String类为什么是不可变类
线程安全类方法的组合
实例分析
售票问题
转账问题
使用的锁必须是A账户和B账户同一把锁,所以将锁加在方法上是不行的,要用Account.class。==使用类锁只能有两个账户同时转账,如果账户很多时会造成性能的低下==
Monitor概念
monitor在操作系统中叫做管程