需要多线程的原因:
- CPU/IO/内存的巨大性能差异
1GHZ的CPU做一次加法需要10亿次/秒(次为cycle, HZ为 1/秒)
1 ns = 10^-9 s
内存的寻址时间
1~10μs = 10^3 ~ 10^4 ns
即内存做一次加法的时间,cpu等了10^3 ~ 10^4个cycle
而HDD需要1ms~10ms=10^6 ns
即普通硬盘做一次加法的时间,cpu等了10^6个cycle
- 多核CPU的发展
- 线程的本质是一个可以执行代码的工人
优点:多个执行流,并发执行;
缺点:
慢:切换上下文典型值1us VS 0.3ns/cycle (cycle时钟周期)
让上下文切换尽可能减少:
协程 又名 用户态线程,但需要重写调度器
占用资源:每个线程有独立的方法栈
Thread
- Thread类的每一个实例代表一个JVM的线程;
start()之后,但未结束;
public static void main(String[] args) {
//↓↓↓这是另一个线程
new Thread(() -> {
while (true){
i++;
}
}).start();
//↓↓↓这是主线程
while (true){
i++;
}
}
- Runnable/Callable都不是线程;
- Thread.start()之后,JVM就增加:
- 一个工人/执行流
- 一套方法栈
java虚拟机中仅存在xxx.main 或thread.run,不会存在第三种情况
- 不同执行流的同步执行是一切线程问题的根源
public class ThreadClass {
static int i = 0;
public static void main(String[] args) {
try {
new Thread(() ->
{ //这里其他线程的异常只能往当前方法栈中抛,catch中无法看到!!
throw new RuntimeException();
}).start();
doSomething();
} catch (Exception e) {
//这里只有主线程doSomething()方法里的异常才能被看到!!
}
}
//两个线程,同时在执行doSomething(),生成了两个不同的栈针,方法内的局部变量是私有的,共享的变量i是公有的;
private static void doSomething() {
i++;
}
}
网友评论