Java高效并发中的“高效”问题:
1. Java中的线程安全:
(“如果多个线程访问一个对象时,...,调用结果都是正确的,则是线程安全”)
(1) 不可变:(final关键字)
(2) 绝对线程安全:(较少,很难,代价很大)
(3) 相当线程安全:(Vector、HashTable等)
(4) 线程兼容:(额外手段使其安全,ArrayList和HashMap)
(5) 线程对立:(无论同步与否,均无法做并发使用)
2. 线程安全的实现方法:(JVM提供的同步和锁机制)
(1) 同步涵义:在多个线程访问共享数据时,能保证数据在同一时刻只被一个线程使用;
(2) 实现方法:
① 互斥同步(阻塞同步:需要时常挂起和恢复)(被动、悲观):
1) sychonized关键字;
2) Java.util.concurrent包中的重入锁(ReentrantLock);
3) 两者考虑:优先考虑sychonized关键字。
② 非阻塞同步(主动、乐观):
使用原子类的方法等,CAS;但无法覆盖互斥同步的所有使用场景
increnebtAndGet()方法等;AtomicInteger代替int。
③ 无同步方案(天生就是线程安全的):
1) 可重入代码:
2) 线程本地储存(“独享”):(将共享数据的可见范围限制在一个线程内)
实现:java.lang.ThreadLocal类
应用的架构模式:
“生产者-消费者”模式
Web“一个请求对应一个服务器线程”
3. 锁优化:(“高效”的体现)
一些优化技术:
(1) 自旋锁:
让请求的那个锁“稍等一下”,无需挂起和恢复,执行一个忙循环(自旋)
(2) 锁消除:
对不可能存在共享的数据竞争进行消除
(3) 锁粗化:
加锁同步范围扩大
(4) 轻量级锁:
1) 使用目的:减少传统的重量级锁使用操作系统互斥产生的性能消耗
2) 问题:更慢了
在无竞争的情况下使用CAS操作去消除同步使用的互斥量
(5) 偏向锁:
1) 使用目的:消除数据在无竞争情况下的同步
在无竞争的情况下把整个同步都消除掉