多线程常见的问题
- 用多线程的目的
- 单核CPU机器上适不适合用多线程
- 适合。如果是单线程,线程中需要等在IO操作,此时CPU就空闲出来了
- 线程什么时候回让出CPU
- 阻塞时、wait、await、等待IO
- sleep
- yield 主动让出
- 运行结束
- 线程是什么
- 最小的执行单元
- 一条代码执行流,完成一组代码的运行
- 这一组代码,可以称为一个任务
- CPU 做的是什么工作
- 线程是不是越多越好
- 线程数量过大,会耗尽 CPU 和内存
- 线程的开启关闭需要时间。如果创建时间+销毁时间 > 执行时间,不合算
- 线程本身需要内存。根据 jvm 规范(64位),一个线程默认最大栈大小1M(32位是320K)
- 操作系统频繁切换线程上下文,影响性能
- 线程回收GC有负担
多线程实现
实现方式
- 在 Java 中要想实现多线程,有两种方式:
- 一种是继承
Thread
类 - 一种是实现
Runable
接口
- 以上两种方式创建的线程,在
run()
方法结束后,自动回收该线程 - 建议:不管是何种方式实现线程,每个线程都要给他一个名字,这对于问题排查系统监控有帮助
- 以上的线程都没有返回,实现
Callable
,有返回的线程(抛异常),见 Future 设计模式相关文章
实现示例
- 继承
Thread
类实现
static class InThreadFromClass extends Thread {
public InThreadFromClass(String name) {
super(name);
}
@Override
public void run() {
System.out.println("继承 Thread 实现线程。 线程名称为: " + Thread.currentThread().getName());
}
}
InThreadFromClass thread = new InThreadFromClass("Thread ");
thread.start();
- 实现
Runable
接口实现
/**
* 实现 Runnable 接口实现
*/
static class InThreadFromRunnable implements Runnable {
@Override
public void run() {
System.out.println("实现 Runnable 接口实现。 线程名称为: " + Thread.currentThread().getName());
}
}
Thread runnable = new Thread(new InThreadFromRunnable(), "ThreadFromRunnable");
runnable.start();
线程管理
- 控制线程的数量:一个系统需要大量的线程来维持其应用。线程数量过大,会耗尽 CPU 和内存
- 每个线程的创建、关闭需要一定的时间。如果线程的数量过多,有可能出现创建销毁线程的时间大于该线程真实工作所消耗的时间,得不偿失
- 线程本身也是要占用内存空间的。大量的线程会抢占内存资源,处理不当,可能会导致OOM(Out of Memory)
- GC 负担。大量的线程回收,会给 GC 带来很大的压力,延长 GC 的停顿
- 推荐使用线程池统一管理线程,而不是显式的创建线程运行,上面的两种运行方式不推荐使用。 见线程池相关博文。
参考
- 源码地址
- Java线程(一):传统线程的实现、互斥与通信
![Fork me on Gitee](https://i-blog.csdnimg.cn/blog_migrate/78e28b188ac32bac09432470d76f1d6d.png)