From:Java并发编程的艺术
- 目录
BiBi - 并发编程 -0- 开篇
BiBi - 并发编程 -1- 挑战
BiBi - 并发编程 -2- volatile
BiBi - 并发编程 -3- 锁
BiBi - 并发编程 -4- 原子操作
BiBi - 并发编程 -5- Java内存模型
BiBi - 并发编程 -6- final关键字
BiBi - 并发编程 -7- DCL
BiBi - 并发编程 -8- 线程
BiBi - 并发编程 -9- ReentrantLock
BiBi - 并发编程 -10- 队列同步器
BiBi - 并发编程 -11- 并发容器
BiBi - 并发编程 -12- Fork/Join框架
BiBi - 并发编程 -13- 并发工具类
BiBi - 并发编程 -14- 线程池
BiBi - 并发编程 -15- Executor框架
1. 线程切换问题
单核处理器通过时间切片可以支持多线程执行。线程在切换之前会保存该任务状态,用于下次切换回来再加载该线程的状态。线程从保存到再次加载的过程称为一次【上下文切换Content Switch】
下面例子中,什么时候考虑将A、B事件放在不同线程中去处理呢?
当N < 1万时,开线程耗时多。
当N > 1千万时,开线程耗时少。【性能提升约1倍】
// A、B事件处理独立
private void test() {
for (int i = 0; i < N; ++i) {
// 处理事件A
}
for (int i = 0; i < N; ++i) {
// 处理事件B
}
}
下载20部电影,是一个一个下载快,还是同时下载20部快呢?
这就要考虑资源的限制,如:
硬件资源限制:服务器带宽(2Mb/s)、硬盘读写速度和CPU的处理速度;
软件资源限制:数据库的连接数、socket连接数。
如果由于资源限制,并行的程序变为串行执行,那么就会增加上下文切换和资源调用的时间,从而导致程序执行更慢.
2. 如何减少上下文切换
1)无锁并发。如ConcurrentHashMap将数据的ID按照Hash算法取模分段,不同的线程处理不同的数据段。
2)CAS【比较并替换 - Compare And Swap】算法。如Java的Atomic包中的AtomicInteger、AtomicBoolean等,不需要加锁。
3)减少线程数量。主要针对线程池的使用,当任务较少而线程较多时,会导致大量线程处于等待状态,从而使性能下降。减少等待状态的线程,能够减少上下文切换次数。【所以,线程池的大小要因需而异】
3. 如何避免死锁
1)避免一个线程同时使用多个锁。
2)避免一个锁同时占用多个资源,尽量保证一个锁只占用一个资源。
3)使用定时锁。
4)数据库锁,加锁和解锁必须在一个数据库连接里。
因为异常导致没有释放锁也会引起死锁现象。