创建线程的两种方式
- 继承Thread类,重写run方法 启动线程直接调用start
- 实现Runnable接口,重写run方法 启动线程时,先Thread thread = new Thread(*),把对象传进去,再用thread.start()来启动线程
重写run方法,写上自己的业务代码
Thread类中的run实现了Runnable接口的run方法
当main线程启动一个子线程,主线程不会阻塞,会继续执行
callable方式创建线程
前两种方式,加入线程执行完毕后有数据需要返回,重写的run方法无法直接返回结果-----Callable接口和FutureTask类可以返回执行完毕后的结果
流程
- 创建任务对象
- 定义一个类实现Callable接口,重写call方法,封装要做的事,和要返回的数据
- 把Callable类型的对象封装成FutureTask对象(线程任务对象)---FutureTask对象实现了Runnable接口
- 后面同上两种方式,把FutureTask对象交给Thread对象
- 调用Thread对象的start方法启动线程
- 线程执行完毕后、通过FutureTask对象的get方法去获取线程任务执行的结果。此处的get方法会等待线程执行完毕再get,保证能拿到结果
优缺点
- 优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后获取线程执行的接口
- 缺点:编码复杂
为什么用start,而不是直接调用run方法
- 直接调用run方法,是用的原线程调用的,就是一个普通的方法,没有真正启动一个线程,就是把run方法执行完毕,才向下执行。
- 使用start才是开启一个新的线程。
继承Thread vs 实现Runnable的区别
- 从java设计来看,继承Thread或者实现Runnable接口来创建线程本质上没有区别,从jdk帮助文档我们可以看到Thread类本身就实现了Runnable接口
- 实现Runnable接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制.
线程终止
- 线程完成任务后,会自动退出
- 还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式
线程常用方法-1
- setName //设置线程名称
- getName
- start //使线程开始执行;java虚拟机底层调用该线程的start0方法
- run
- setPriority
- getPriority
- sleep
- interrupt// 中断线程
注意-1
- start底层会创建新的线程,调用run,run就是一个简单方法的调用,不会启动新线程
- 线程优先级范围
- interrupt, 中断线程,并没有真正结束线程,所以一般用于中断正在休眠的线程
- sleep: 线程的静态方法,使当前线程休眠
线程常用方法-2
- yield:线程的礼让。让出cpu,让给其他线程执行,但礼让的时间不确定,所以也不一定礼让成功
- join:线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程的所有任务。
用户线程和守护线程
- 用户线程:也叫工作线程,当线程的任务执行完或通知方式结束
- 守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束
- 常见的守护线程:垃圾回收机制
线程的生命周期
七个状态,官网文档把Ready和Running看做一个Runnable状态
所以Runnable状态不一定就在执行,Ready到Running由线程调度器调度
本文章使用limfx的vscode插件快速发布