Runnable接口定义线程任务逻辑,不启动线程也不管理生命周期,仅封装run()方法;因Java单继承限制及职责分离优势,优先于继承Thread类;需手动处理异常、中断和同步。

Runnable接口是用来定义线程任务逻辑的契约
它不启动线程,也不管理生命周期,只规定“做什么”——即把要并发执行的代码封装进run()方法。JVM或线程调度器在真正执行时,会调用这个方法,但不会捕获它的异常,也不会返回结果。
为什么不用继承Thread类而选Runnable
Java单继承限制下,若类已继承其他父类(比如SwingWorker或自定义业务基类),就无法再extends Thread;而实现Runnable是接口,可与任意继承关系共存。另外,Runnable更符合面向对象的职责分离:任务逻辑(what)和执行机制(how)解耦。
-
new Thread(new MyTask()).start()是最简用法,但每次启动都新建线程,开销大 - 配合
ExecutorService使用才是主流:executor.submit(new MyTask()),复用线程池 -
Runnable实例可被多次提交(只要没状态),而Thread对象只能start一次
Runnable.run()里抛出异常会导致线程静默终止
这是最容易忽略的坑:run()声明不抛受检异常,且JVM对未捕获的RuntimeException不做任何处理——线程直接退出,控制台可能完全无输出。调试时若发现线程“莫名消失”,第一反应应是检查run()内部是否发生了空指针、数组越界等。
- 务必在
run()开头加try-catch(Throwable t)并至少打日志:log.error("task crashed", t) - 不要依赖
Thread.setDefaultUncaughtExceptionHandler()来兜底,它不触发于ExecutorService中的任务(除非你用execute()而非submit()) -
Callable才是需要返回值+异常传播的替代方案,但需配合Future获取结果
Runnable本身没有状态管理能力
它只是一个函数式接口(从Java 8起标注了@FunctionalInterface),编译后就是个普通类,不带线程上下文、不保存运行时堆栈、也不感知中断信号。所谓“中断”靠的是外部调用thread.interrupt(),而run()里必须主动检查Thread.currentThread().isInterrupted()或响应InterruptedException(如在sleep()中)。
立即学习“Java免费学习笔记(深入)”;
- 不要在
run()里写无限循环却不判断中断状态,否则interrupt()无效 - 共享变量需自行加
volatile或用Atomic*,Runnable不提供任何同步保障 - Lambda表达式创建
Runnable很常见,但注意闭包捕获的局部变量必须是effectively final










