目录
Thread类
Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。
Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。
构造方法
- Thread() 创建线程对象
- Thread(Runnable target) 使用Runnable创建线程对象
- Thread(String name) 创建一个有名字的线程
- Thread(Runn target , String name) 创建线程并命名
让一个线程有名字对线程的执行没有任何影响, 意义就是为了让调试方便
常见方法获取属性
- getId() 返回ID
- getName() 返回name
- getState() 返回状态
- getPriority() 返回优先级
- isDaemon() 是否后台线程
- isAlive() PCB是否存活
- isInterrupted() 是否被中断
- ID 是线程的唯一标识,不同线程不会重复
- 名称是各种调试工具用到
- 状态表示线程当前所处的一个情况,下面我们会进一步说明
- 优先级高的线程理论上来说更容易被调度到
- 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
- 是否存活,即简单的理解,为 run 方法是否运行结束了
- 线程的中断问题,下面我们进一步说明
启动线程 start()
- 定义的新线程thread与原有线程之间是并发执行,只有新线程调用start()方法后,才能真正在内核中创建线程
- 如果是使用thread.run() 就上面代码而言执行结果是一样的,但本质不一样, 这样的方式只是一个普通的方法调用,没有创建新的线程,输出语句是在原有线程里执行的
- 而使用start() 方法时创建一个新线程,输出语句由新线程执行
中断线程 interrupt()
目前常见的俩种中断线程的方式:
通过共享的标记来进行沟通(温和)
- 这种方式比较温和,就是让run方法执行完,例如下面的例子当新线程的sleep执行到100ms时, 我们把isQuit 改为true 但是当前线程并不会立即停止退出,而是把剩下的900ms等待玩,才会结束线程
调用 interrupt() 方法来通知(刚烈)
此时线程会有俩种情况
- 当前线程在sleep 或者 wait 中, 这种情况中断就是给线程触发一个异常,线程就会收到这个异常,针对这个异常如何处理就是catch里的事情了
- 当前线程不在sleep或者wait 这个操作会将isInterrupted置为true 来中断线程
本质上上面两个动作在一个线程里是同时工作的
重点说明下第二种方法:
- 通过 thread 对象调用 interrupt() 方法通知该线程停止运行, thread 收到通知的方式有两种:
- 如果线程调用了 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通知,并清除中断标志
- 否则,只是内部的一个中断标志被设置,thread 可以通过以下俩种方式退出run
-
Thread.interrupted() 判断当前线程的中断标志被设置,并清除中断标志(中断一次将中断结果显示为true,但同时又将中断标记设回false)
-
Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志(不清楚中断标记的意思是只要中断一次将.isInterrupted()改为了true就一直会是true)(推荐, 通知收到的更及时,即使线程正在 sleep 也可以马上收到 )
- 注意一点 如sleeo(5000) 不会真正达到5000ms 误差在10ms以内
-
- 如果我们要保证run那段程序的原子性,就推荐使用温和的方式中断线程