创建线程的方式有几种?区别是什么?
答案
Java 中创建线程的方式主要有 4 种:
- 继承 Thread:直接继承,重写 run(),简单但不灵活。
- 实现 Runnable:接口实现,解耦任务和线程,无返回值。
- 实现 Callable:接口实现,支持返回值和异常处理。
- 线程池:复用线程,高并发下高效管理。
具体区别
1. 实现方式
- Thread:继承类,重写 run(),创建即线程对象。
- 示例:new MyThread().start()。
- Runnable:实现接口,传入 Thread 构造器。
- 示例:new Thread(new MyRunnable()).start()。
- Callable:实现接口,结合 FutureTask 包装。
- 示例:new Thread(new FutureTask<>(new MyCallable())).start()。
- 线程池:通过 ExecutorService 提交任务。
- 示例:executor.submit(runnable)。
2. 功能支持
- Thread:仅执行任务,无返回值。
- Runnable:仅执行任务,无返回值。
- Callable:支持返回值(通过 Future.get() 获取)和异常抛出。
- 线程池:支持任务管理(提交、取消)、返回值(若用 Callable)。
3. 灵活性
- Thread:耦合高,不能继承其他类。
- Runnable:解耦任务和线程,可继承其他类。
- Callable:功能更强,但需额外 FutureTask。
- 线程池:高度灵活,动态调整线程数。
4. 性能与资源
- Thread:每次创建新线程,开销大(约 1MB 栈内存)。
- Runnable:仍需手动创建线程,开销同上。
- Callable:同上,但逻辑复杂。
- 线程池:复用线程,减少创建/销毁开销,适合高并发。
5. 使用场景
- Thread:简单单次任务。
- Runnable:通用任务,推荐基础方式。
- Callable:需要结果或异常处理的异步任务。
- 线程池:高并发、批量任务(如 Web 服务)。
延伸与面试角度
- 其他方式?:
- 严格来说,只有 Thread 和 Runnable 是基础方式,Callable 和线程池是扩展。
- 选择依据:
- Thread:简单任务,少用。
- Runnable:通用,解耦任务和线程。
- Callable:需要返回值或异常。
- 线程池:高并发,资源复用。
- 优缺点:
- Thread:耦合高,每次新建开销大。
- Runnable:灵活,但无返回值。
- Callable:功能强,但复杂。
- 线程池:性能优,但需管理。
- 实际应用:
- Spring 用线程池(TaskExecutor)异步处理。
- Fork/Join 框架基于线程池。
- 面试点:
- 问“区别”时,提继承 vs 接口、返回值。
- 问“线程池优势”时,提复用和资源控制。
- Callable vs Runnable?:
- Callable 有返回值,Runnable 无,适合不同需求。
- 线程池优势?:
- 复用线程,控制并发数,避免线程爆炸。
- 为什么 Runnable 优于 Thread?
- 解耦任务逻辑和线程控制,符合面向接口编程。