cpu、进程、线程
概念
并发编程的目的是让程序变得更快,同样的工作量,一个人忙活肯定没有两个人快,当然也是有前提的,简单介绍下概念
举个例子:
10瓶啤酒,1把起子,一个人只能用一把起子,打开1瓶啤酒1秒,10瓶10秒;
要是有两把起子呢,如果还是一个人,一个人只能用一把起子,起子再多也没用,还是10秒;
如果有两个人,两把起子呢,那一人拿一把起子,没人开5瓶,同时开,就只需要5秒;
将用人想成我们的程序,程序控制用几个人,一个人单线程,多个人多线程;将啤酒想成任务,需要达成的结果;将起子想成cpu核,开啤酒瓶需要起子,完成任务需要cpu来执行我们的程序,当起子够多,人够多,就能多人同时使用起子开啤酒;当cpu核数够多,线程开的够多,完成任务就快,理论如此,但看下面例子:
public class SpeedTest {
/** 累加次数 */
private static long count = 10000 * 10000 * 10;
public static void main(String[] args) throws InterruptedException {
//并行
concurrent();
//串行
serial();
}
private static void concurrent() throws InterruptedException {
Long start = System.currentTimeMillis();
Thread thread = new Thread(() -> {
long a = 0L;
for (int i = 0; i < count; i++) {
a += 1;
}
System.out.printf("concurrent, a=%s%n", a);
});
thread.start();
long b = 0L;
for (int i = 0; i < count; i++) {
b += 1;
}
thread.join();
Long end = System.currentTimeMillis();
System.out.printf("concurrent, b=%s, count=%s, time=%sms%n", b, count, end - start);
}
/**
* 串行
*/
private static void serial() {
long a = 0L;
long b = 0L;
Long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
a += 1;
}
System.out.printf("serial, a=%s%n", a);
for (int i = 0; i < count; i++) {
b += 1;
}
Long end = System.currentTimeMillis();
System.out.printf("serial, b=%s, count=%s, time=%sms%n", b, count, end - start);
}
}
不同count下的耗时:
Connected to the target VM, address: '127.0.0.1:51419', transport: 'socket' concurrent, b=100000000, count=100000000, time=127ms serial, b=100000000, count=100000000, time=90ms Disconnected from the target VM, address: '127.0.0.1:51419', transport: 'socket'
Connected to the target VM, address: '127.0.0.1:51369', transport: 'socket' concurrent, b=1000000000, count=1000000000, time=527ms serial, b=1000000000, count=1000000000, time=852ms Disconnected from the target VM, address: '127.0.0.1:51369', transport: 'socket'
如此,count = 1亿时,还是串行快的。
cpu时间片分配
仔细想下,当只有一把起子的时候,就不能有多个人吗?当然可以,起子可以轮着用,你开一瓶啤酒,再给我开一瓶啤酒,类比cpu,当只有单核cpu时,多个线程是先给你执行下,在给我执行下,交换的来,这叫cpu时间片分配;
上下文切换
按一定的算法给每个线程分配时间;再来比如我起瓶盖刚起一半,起子就交给了你,甭管你咋用,再次到我手上的时候,我就不会重新起了,因为我给你起子时已经记录下了正在起的是哪一瓶,瓶盖上哪个位置,直接从上次的位置开始起,很严谨,类比cpu,当 cpu时间结束时,会记录该线程当任务状态,当cpu再次轮询到该线程时,直接从上次结束的位置接着执行,这里任务状态从保存到再次加载的过程就叫cpu的一次上下文切换;这里就能发现,多线程不一定快,因为上下文切换也需要时间,资源不够时,线程开再多,反而会更慢;
线程、进程
再来比如现在有一间屋子里一帮人在开啤酒瓶,隔壁屋子一帮人在开可乐,就一把起子,起子就这样两屋子递来递去,这就是单核cpu在执行两个进程的程序,里面的人就是线程,所以,一个进程可以有多个线程,线程是进程里的,因为cpu运转非常快,每个时间片毫秒级别,所以即使单核cpu也能同时兼顾多个程序,并感觉不出来。

浙公网安备 33010602011771号