第一章
并发编程的目的是为了让程序运行得更快,但并不是启动更多的线程就能让程序最大限度的并发执行。
由于我们的目的是为了提升程序性能,所以程序运行的细节都需要把握清楚。
1.1上下文切换
CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。
- 多线程一定快吗?
下面给出一组测试代码
package ChapterI;
public class ConcurrentTest {
private static final long count = 10000l;
public static void main(String[] argc) throws InterruptedException {
concurrency();
serial();
}
//单线程执行
private static void serial() {
long start = System.currentTimeMillis();
long a = 0;
for (long i = 0; i < count; i++) {
a += 5;
}
long b = 0;
for (long i = 0; i < count; i++) {
b--;
}
long end = System.currentTimeMillis();
System.out.println("serial :" + (end - start) + "ms b = " + b + " a = " + a);
}
//多线程执行
private static void concurrency() throws InterruptedException {
long start = System.currentTimeMillis();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
long a = 0;
for (long i = 0; i < count; i++) {
a += 5;
}
}
});
thread.start();
long b = 0;
for (long i = 0; i < count; i ++){
b --;
}
long end = System.currentTimeMillis();
thread.join();//等待线程执行完毕
System.out.println("Concurrency :" + (end - start) + "ms b = " + b);
}
}
count = 1_0000
Concurrency :1ms serial :0ms
count = 10_0000
Concurrency :7ms serial :5ms
count = 100_0000
Concurrency :13ms serial :11ms
count = 1000_0000 (测试数据其实两者相差不多,有时并行更快,可能是有优化?)
Concurrency :11ms serial :16ms
count = 1_0000_0000
Concurrency :65ms serial :118ms
count = 10_0000_0000
Concurrency :589ms serial :873ms
从数据库中可以看到,当达到1亿之后串行速度明显变快。由于测试用例的原因和电脑性能的问题可能提升不是特别明显。
-
为什么上面例子在达到一定数量级时并行会比串行慢?
因为线程有创建和上下文切换的开销 -
如何测试上下文切换次数和时长?
- 使用Lmbench3测量时长
- 使用vmstat测试切换次数
-
如何减少上下文切换
- 无锁并发编程
- CAS算法(乐观锁)
- 使用最少线程
- 协程
知识点突破
BLOCKED,WAITING,TIMED_WAITING有什么区别?-用生活的例子解释
如何使用jstack分析线程状态
awk从放弃到入门(1):awk基础 (通俗易懂,快进来看)
每天一个linux命令:vmstat