多线程
进程和线程
一个进程下包含多个线程,进程间通信复杂,需要用rpc,http等协议通信,线程间通信可以通过进程中的共享变量。
上下文切换
1. 暂停一个进程的处理,并将该进程的CPU状态(即上下文)存储在内存中的某个地方
2. 从内存中获取下一个进程的上下文,并在CPU的寄存器中恢复它
3. 返回到程序计数器指示的位置(即返回到进程被中断的代码行)以恢复进程/线程。
就CPU时间片而言,一次上下文切换大概需要5000~20000个时钟周期,相对一个简单指令几个乃至十几个左右的执行时钟周期,可以看出这个成本的巨大。
并发和并行
并发包含并行,并发更强调逻辑上同时发生,并行更强调物理上同时发生,并发包括了cpu单核宏观看同时运行的线程,微观上其实是cpu切换串行执行多任务的
线程的创建和启动
使用Thread类
Thread thread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
});
thread.start();继承Runnable
Thread是线程,Runnable是任务,拆分开使用
Runnable runnable = () -> {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
};
new Thread(runnable).start();FutureTask
FutureTask<Integer> task = new FutureTask<>(() -> {
System.out.println("hello");
return 100;
});
new Thread(task).start();
Integer result = task.get();
System.out.println("结果是:" + result);创建线程总体就一种,new Thread,但是里面是Callable和Runnable就分两种,Callable能返回结果,Runnable不能,Callable线程不支持接收作为参数,所以用FutureTask包装。
run和start
只有start方法才是启动线程,调用操作系统分配cpu,分到了cpu才调用run方法,手动调用run方法也能执行,但没有分到线程,run本质上就是一个方法。
重复调用一个线程的start方法会报错:

线程不是NEW的状态了,不让start。
线程的状态/生命周期
操作系统层面
初始状态:语言层面创建了线程对象,还没和操作系统关联
可运行状态:(准备就绪)随时可以运行任务
运行状态:获取了cpu时间片,正在运行任务
阻塞状态:因io而阻塞,让出cpu,直到被唤醒
终止状态:线程执行完毕,进入终止状态,不会再转变其它状态
java语言层面
初始状态(NEW):new了,但是没调用start
运行状态(RUNNABLE):java把可运行和运行合二为一,都叫运行状态
阻塞(BLOCKED):表示线程阻塞于锁
等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
终止(TERMINATED):表示该线程已经执行完毕。
评论