一. 概念与基础
book: 《Java并发编程实践》
《Java并发编程实践》笔记(Note of 《Java Concurrency in Practice》)(1-5章)
1)程序次序法则:
线程中每个动作A都happens-before于该线程中的每一个动作B,其中,在程序中,所有的动作B都出现在动作A之后。
2)监视器锁法则:
对一个监视器锁的解锁happens-before于每一个后续对同一监视器锁的加锁。
3)volatile变量法则:
对volatile域的写入操作happens-before于每一个后续对同一个域的读操作。
4)线程启动法则:
在一个线程里,对Thread.start的调用会happens-before于每一个启动线程中的动作。
5)线程终结法则:
线程中的任何动作都happens-before于其他线程检测到这个线程已经终结、或者从Thread.join调用中成功返回,
或者Thread.isAlive返回false。
6)中断法则:
一个线程调用另一个线程的interrupt happens-before于被中断的线程发现中断
(通过抛出InterruptedException,或者调用isInterrupted和interrupted)。
7)终结法则:
一个对象的构造函数的结束happens-before于这个对象finalizer的开始。
8)传递性:
如果A happens-before于B,且B happens-before于C,则A happens-before于C。
book: 《Java虚拟机并发编程》
1. 确定线程数:
线程数=CPU可用核心数(Runtime.getRuntime().availableProcessors())/(1-阻塞系数)
阻塞系数取值范围为 (0-1),计算密集型任务的阻塞系数为0,IO密集型任务的阻塞系数接近1.
2. 确定任务数量:
使处理器一直保持忙碌状态比将负载均衡到每个子任务要实惠,尽可能对问题进行拆分以产生足够多的工作供处理器可用核心来执行。
1) 子任务的划分数应不少于处理器核心数;
2) 线程数多于处理器核心数对性能提升毫无帮助;
3) 在子任务划分数超过一定数量后,再增加子问题划分数对于性能的提升将十分有限。
3. 设计方法:
1) 共享可变性方法
2) 隔离可变性方法: 需保证可变变量切实被隔离开,且绝不会被超过一个线程访问。
3) 纯粹不可变性方法
4. Java7 Fork-Join API 非常适合于解决那些可以递归分解至小到足以顺序运行的问题。
5. 使用显示同步注意事项:
1) 在静态工厂方法而不是构造函数中创建线程;
2) 不要随意创建线程,而是使用线程池来降低任务启动时间和资源消耗;
3) 确保对可变字段的访问跨越内存栅栏,并对线程可见;
4) 通过正确评估程序所需要的锁的粒度来提高程序的并发度;
5) 当需要多个可变字段时,请核实对这些变量的访问是否是原子的,即要保证其他线程不会看到这些变量的部分修改结果。
6. STM 软件事务内存: 是一个针对并发问题的非常强大的编程模型,优点:
1) STM可以根据应用程序的行为来充分挖掘出其最大的并发潜力;
2) STM是一种锁无关的编程模型,可以提供良好的线程安全性和很高的并发性能;
3) STM可以保证实体仅能在事务内被更改;
4) STM没有显式锁意味着我们从此无需担心加锁顺序及其他相关问题;
5) STM没有显式锁的结果是无死锁的并发执行;
6) STM可以帮助我们减轻前期设计的决策负担,无需关心上锁,只需放心地交给动态隐式组合锁;
7) STM适用于对相同数据存在并发读且写冲突不频繁的应用场景。
8) Java版本的STM框架: Akka/Multiverse
二. “神器” in JDK
Java 理论与实践: JDK 5.0 中更灵活、更具可伸缩性的锁定机制
ConcurrentHashMap
HashMap和ConcurrentHashMap的并发性能测试
ConcurrentMap.putIfAbsent(key,value) 用法讨论 (要根据该方法的返回值进行处理,如下:)
public class Locale implements Cloneable, Serializable { private final static ConcurrentMap<String, Locale> map = new ConcurrentHashMap<String, Locale>(); public static Locale getInstance(String language, String country, String variant) { //... String key = some_string; Locale locale = map.get(key); if (locale == null) { locale = new Locale(language, country, variant); map.putIfAbsent(key, locale); } return locale; } // .... }
CopyOnWriteArrayList
与Collections.synchronizedMap性能比较
ConcurrentLinkedQueue
CompleteService
Callable
CyclicBarrier
淘宝面试题:如何充分利用多核CPU,计算很大的List中所有整数的和
ScheduledExecutorService
ScheduledExecutorService执行定时任务
在Timer和ScheduledExecutorService间抉择
三. 常见问题
1. 关于多线程环境中的单例
2. Thread Dump
How to Analyze Java Thread Dumps
3. 惰性初始化holder类技巧
@ThreadSafe public class ResourceFactory { private static class ResourceHolder { public static Resource resource = new Resource(); } public static Resource getResource() { return ResourceHolder.resource; } }