----------------------------------------------《Java并发编程实战》读书笔记------------------------------------------------------------------------------
第二章 线程安全性
java同步 1、sychronized
2、volatile类型
3、显示锁
4、原子变量
性能优化之原则:首先保证代码能正确运行,然后再提高代码速度。并且,只是当性能测试结果和应用需求需要提高性能、
并且测量结果表明该种优化在实际环境中确实能够带来性能提升时,才进行优化。
1、无状态对象一定是线程安全的,例如无状态servlet (大多数servlet都是无状态的)
2、原子性
比如 count++就不是原子性操作,它包括了 读取count —— count值+1 —— 新值放回count 三个操作
这样的非原子操作在多线程环境下就会出现线程安全性问题
并发编程中,由于多个线程交替执行不恰当的执行时序而出现不正确的结果,称为竞态条件。
最常见的一种静态条件: 先检查,后执行。 即通过一个可能已经是失效的监测结果来决定下一步的执行动作。
原子变量
多线程累加计数使用java.util.concurrent.atomic.AtomicLong类型代替long,其incrementAndGet()方法实现自增加1,这是线程安全的。
原子变量不能解决所有并发问题,只能对某个变量进行原子操作,如果是一段过程,则没法进行原子操作。多个变量进行依赖的情况也无能为力。
例子:(在一个servlet.service()方法里,建两个AtomicReference存一对值key-value,每次查询key命中就返回value,如果不命中就设置新的key-value)
3、 内置锁
即代码同步块synchronized ,是一种互斥机制,任何一个执行同步代码块的线程,都不可能看到其他线程在执行由同一个锁保护的同步代码块。
好比是一个每次只能出现一个人的房间,其他人要想进入这个房间,必须等里面的这个人出去,并且每次房间里最多只能有一个人。
e.g. 可以把上面的那个servlet的service()方法设置为public synchronized void service(),保证了线程安全性,但性能太低。
每次只有一个线程能访问service方法,而service又是servlet的主要方法,这相当于servlet变成单线程的了
4、 重入
指的是java内置锁的一种特性,线程在重复获取一个已经由它持有内置锁的时候,是可以成功的。
public class Widget{
public synchronized void doSomething(){}
}
public class LoginWidget extends Widget{
public synchronized void doSomething(){
...
super.doSomething();
}
}
子类调用自己的doSomething方法持有锁,然后在方法体内再调用父类的doSomething方法,请求的是同一个锁,
如果没有重入特性,那么此处将会发生死锁。
5、 同步的两个方面
1、线程安全性
2、内存可见性(memory visibility)
线程在使用一个资源的时候其他线程不可以修改这个资源;同时,当线程对一个资源的状态进行了修改之后,其他线程应该可以看得见这个变化。即为内存可见性。