关于并发编程,其目的就是为了让程序运行得更快,但是,并不是启动更多的线程就能让程序更大限度的并发执行。有哪些影响并发编程的因素呢?
一、文章导图
二、挑战
1、上下文切换
单核处理器也支持多线程执行代码,CPU 通过给每个线程分配 CPU 时间片来实现这个机制,只是时间片的时间短,感觉 CPU 能同时处理多个任务。时间片一般是几十毫秒(ms)。
CPU 通过时间片轮训的方式处理任务,当前任务执行一个时间片会切换到下一个任务。注意,当 CPU 从一个任务切换到另一个任务前,会保留上一个任务的状态,以便再切回来是可以继续执行。所以任务从保持状态到再加载的过程就是一次 上下文切换。
- 多线程执行耗时测试
电脑配置:单处理器双核 8G 内存
public class Demo1_1_1 {
private static final long count = 1000000001;
public static void main(String[] args) throws InterruptedException {
// 注释一个进行执行
concurrent();
// serial();}
/**
* 并发执行
*/
private static void concurrent() throws InterruptedException {long start = System.currentTimeMillis();
Thread thread = new Thread(() -> {
int a = 0;
for (long i = 0; i < count; i++) {a += 5;}
});
thread.start();
int b = 0;
for (long i = 0; i < count; i++) {b --;}
thread.join();
System.out.println("concurrent time:" + (System.currentTimeMillis() - start) + "ms");
}
/**
* 串行执行
*/
private static void serial() {long start = System.currentTimeMillis();
int a = 0;
for (long i = 0; i < count; i++) {a += 5;}
int b = 0;
for (long i = 0; i < count; i++) {b --;}
System.out.println("serial time:" + (System.currentTimeMillis() - start) + "ms");
}
}
以上分别执行 3 次,取一个最大值和一个最小值
结果
循环次数 | 并行耗时 /ms | 串行耗时 /ms |
---|---|---|
10 万 | 66 – 90 | 2 – 4 |
100 万 | 68 – 78 | 5 – 13 |
1000 万 | 75 – 81 | 16 – 19 |
1 亿 | 133 – 128 | 80 – 121 |
10 亿 | 600 – 615 | 900 – 1000 |
分析
当并发执行不超过亿级别时,并行是比串行慢的,这就是因为线程有创建和上下文切换的开销。按理说多个线程执行应该比单线程慢,实际并非如此。
- 如何减少上下文切换
1、无所并发编程:多线程竞争锁时,会引发上下文切换
2、CAS 算法:Java 中的 Atomic 包使用 CAS 算法更新数据,无需加锁
3、使用最少线程:任务少,但线程多,导致很多线程都处于等待状态
4、协程:在线程里实现多线程的调度
2、死锁
java 中的锁主要用来解决并发编程资源竞争的问题,如果编程不当,一旦产生死锁,便会导致系统功能不可用。
例如,有两个线程 t1,t2;两个资源 A,B;当出现,t1 持有 A 资源,t2 持有 B 资源时,t1 尝试获取 B 资源,t2 尝试获取 A 资源,此时,便会出现死锁的情况。
- 避免死锁的办法
1、避免一个线程同时获取多个锁
2、避免一个线程在锁内同时占有多个资源,尽力保证每个线程只占用一个资源
3、尝试使用定时锁,如 lock.tryLock(timeout)
3、资源限制的挑战
- 什么是资源限制
资源限制指在进行并发编程时,程序的执行速度受限于计算机硬件资源或软件资源。
硬件资源包括:带宽的上传下载速度、硬盘读写速度和 CPU 的处理速度等
软件资源包括:线程池大小、数据库的连接数等
- 资源限制引发的问题
在并发编程中,代码执行速度加快的原则是将代码中的串行部分变成并行执行,但有可能由于资源限制问题,导致程序仍按串行执行,此时程序不仅不会变快,反而更慢,因为增加了上下文切换和资源调度的时间。
- 如何解决资源限制的问题
对于硬件资源限制:考虑使用集群方式并行执行程序。
对于软件资源限制:考虑使用资源池将资源复用,例如数据库连接池等
- 资源限制情况下进行并发编程
根据不同的资源限制调整程序的并发度。