第一章:零碎的知识点
1.无状态对象一定是线程安全的,比如函数内的局部变量保存在线程栈中,只能有当前线程访问。
2.一些线程不安全的例子:
i++ 的执行顺序是读取i;修改i++;写入i=i++;
这三个操作并非原子操作,最后i的状态依赖于之前的状态。显然多个线程i++,将出现很多意想不到的结果。
3.竞态条件
常见的竞态条件类型就是,先检查后执行。if(xxx){ doSomething; }
即,程序的执行正确性取决于多个线程的交替执行时序。
4.复合操作:避免竞态条件问题,需要将这组操作以原子方式执行。
如:原子变量类 AtomicLong count= new AtomicLong(0);
count.incrementAndGet(); //复合:增加,返回值
5.加锁机制
使用原子变量类未必线程安全:
原子变量1 .set(val);
原子变量2.set(val2);.//两个原子变量中间存在竞态
6.内置锁
jvm层面实现的内置锁:同步代码块sychronized block,由两个部分组成
6.1 作为锁的对象引用
6.2作为由这个锁保护的代码块//synchronized(lock){}
内置锁相当于互斥锁,最多只有一个线程可以持有这个锁。//public synchronized void fun(){}
7.内置锁重入
可重入意味着获取锁的操作粒度是线程,而不是调用。
内置锁必须是可重入的,例子:子类重写了父类加同步的方法,然后子类调用父类的方法。
如果没有重入,将产生死锁。同时,重入也提升了加锁的封装性,简化面向对象的并发。
8.用锁来保护状态
常见的加锁约定:将所有可变的状态封装在对象内部,通过对象的内置锁对所有可变状态进行同步。
如 vector
9.