5.线程启动(statrt方法)
start方法内部,会调用系统api来在系统内核中创建出线程,创建完线程后会自动调用run方法。
而run方法,就只是描述这个线程要执行的任务。
start 和 run 得区别(经典面试题):
1.作用功能不同:
- run 方法的作用是描述线程具体要执行的任务
- start 方法的作用是申请系统线程
2.运行结果不同:
- run 方法是一个类中的普通方法,主动调用和调用普通方法一样,会按顺序执行一次
- start 调用方法后,start 方法内部会调用Java 本地方法(封装类对系统底层的调用)真正的启动线程,并执行run 方法中的代码,run 方法执行完后线程就销毁。
6.打断线程(interrupt方法)
在Java中想让一个线程停止运行,需要run 方法尽快结果,执行的任务结束线程也就结束了。
- 使通过共享的标记位进行沟通
通过改变isVaild 的值结束线程,上面代码是内部类访问外部类的属性。
上面是通过访问"外部"变量修改线程,使线程停止运行(如图1)。看图1会发现报错了,这个就是变量捕获所产生的问题。解决:只要将isVaild 设置成final 变量 或者不修改它的值就不会产生变量捕获问题(如图2).
变量捕获
在lambda 表达式里面的代码可以自动捕获作用域中涉及的外层变量。使用lambda 表达式需要遵循一个语法规则:变量捕获。
变量捕获:lambda 表达式把当前作用域中的变量在lambda 内部复制一份,所以在lambda 表达式中如果一个变量的值是一直变化的就会出现问题,所以Java中变量捕获的限制是只能捕获一个final 修饰的变量或者是一个没有修改内容的变量(也叫实际上是final 的变量)
使用标志位结束线程这个方法有不足的地方:
- 需要手动创建标志位变量
- 当线程内部sleep 时,主线程修改变量,新线程内部不能及时响应。也就是当主线程中停止已经开始了,lambda 表达式还在执行,主线程就要等到 run方法执行完才能开始。
- 调用interrupt 方法来通知
使用interrupt 即使线程内部出现sleep 也可以终止线程。也就是说sleep 会休眠到时间才能唤醒,interrupt就可以使内部触发一个异常(InterruptedException),从而提前结束该线程。
使用Thread.isInterrupted() 线程中断会自动清除标志位,而使用Thread.current().isInterrupted() 不会。
7.等待线程(join方法)
让一个线程等待另一个线程执行结束再继续执行,本质上就是控制线程结束的顺序。如果主线程中调用t.join() ,此时主线程就要等待t 线程结束再执行后面代码,join默认是带有超时的等待。
如果t 线程正在运行中,此时调用join 的线程就会阻塞(像主线程就是调用了join方法),一直等到t 线程结束为止;如果t 线程已经结束了,此时调用join 线程就直接往后走了不会阻塞。