1、Java 程序天生就是多线程的
一个 Java 程序从 main()方法开始执行,然后按照既定的代码逻辑执行,看 似没有其他线程参与,但实际上 Java 程序天生就是多线程程序,因为执行 main() 方法的是一个名称为 main 的线程。
- [6] Monitor Ctrl-Break //监控 Ctrl-Break 中断信号的
- [5] Attach Listener //内存 dump,线程 dump,类信息统计,获取系统属性等
- [4] Signal Dispatcher // 分发处理发送给 JVM 信号的线程
- [3] Finalizer // 调用对象 finalize 方法的线程
- [2] Reference Handler//清除 Reference 的线程
- [1] main //main 线程,用户程序入口
注意:jdk线程是协作式,不是抢占式
2、线程的启动与中止
1、启动
启动线程的方式有:
1、X extends Thread;,然后 X.start
2、X implements Runnable;然后交给 Thread 运行
3、run():直接调用就是一个普通方法,可以多次调用;
4、start():调用就是启动一个线程,只能调用一次;
2、Thread 和 Runnable 的区别
Thread 才是 Java 里对线程的唯一抽象,Runnable 只是对任务(业务逻辑) 的抽象。Thread 可以接受任意一个 Runnable 的实例并执行。
3、终止
1、线程自然终止 要么是 run 执行完成了,要么是抛出了一个未处理的异常导致线程提前结束。
2、stop 暂停、恢复和停止操作对应在线程 Thread 的 API 就是 suspend()、resume() 和 stop()。但是这些 API 是过期的,也就是不建议使用的。不建议使用的原因主 要有:以 suspend()方法为例,在调用后,线程不会释放已经占有的资源(比如 锁),而是占有着资源进入睡眠状态,这样容易引发死锁问题。同样,stop()方 法在终结一个线程时不会保证线程的资源正常释放,通常是没有给予线程完成资 源释放工作的机会,因此会导致程序可能工作在不确定状态下。正因为 suspend()、 resume()和 stop()方法带来的副作用,这些方法才被标注为不建议使用的过期方 法。
3、中断 安全的中止则是其他线程通过调用某个线程 A 的 interrupt()方法对其进行中 断操作, 中断好比其他线程对该线程打了个招呼,“A,你要中断了”,不代表 线程 A 会立即停止自己的工作,同样的 A 线程完全可以不理会这种中断请求。 因为 java 里的线程是协作式的,不是抢占式的。线程通过检查自身的中断标志 位是否被置为 true 来进行响应,
4、 线程通过方法 isInterrupted()来进行判断是否被中断,也可以调用静态方法 Thread.interrupted()来进行判断当前线程是否被中断,不过 Thread.interrupted() 会同时将中断标识位改写为 false。
5、 如果一个线程处于了阻塞状态(如线程调用了 thread.sleep、thread.join、 thread.wait 等),则在线程在检查中断标示时如果发现中断标示为 true,则会在 这些阻塞方法调用处抛出 InterruptedException 异常,并且在抛出异常后会立即 将线程的中断标示位清除,即重新设置为 false。
6、不建议自定义一个取消标志位来中止线程的运行。因为 run 方法里有阻塞调 用时会无法很快检测到取消标志,线程必须从阻塞调用返回后,才会检查这个取 消标志。这种情况下,使用中断会更好,因为,
一、一般的阻塞方法,如 sleep 等本身就支持中断的检查,
二、检查中断位的状态和检查取消标志位没什么区别,用中断位的状态还可 以避免声明取消标志位,减少资源的消耗。
注意:处于死锁状态的线程无法被中断
3、yield()方法:
使当前线程让出 CPU 占有权,但让出的时间是不可设定的。也 不会释放锁资源。注意:并不是每个线程都需要这个锁的,而且执行 yield( )的线 程不一定就会持有锁,我们完全可以在释放锁后再调用 yield 方法。 所有执行 yield()的线程有可能在进入到就绪状态后会被操作系统再次选中 马上又被执行。
4、join 方法
把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行。 比如在线程 B 中调用了线程 A 的 Join()方法,直到线程 A 执行完毕后,才会继续 执行线程 B。(此处为常见面试考点)
5、线程的优先级
在 Java 线程中,通过一个整型成员变量 priority 来控制优先级,优先级的范 围从 1~10,在线程构建的时候可以通过 setPriority(int)方法来修改优先级,默认 优先级是 5,优先级高的线程分配时间片的数量要多于优先级低的线程。
设置线程优先级时,针对频繁阻塞(休眠或者 I/O 操作)的线程需要设置较 高优先级,而偏重计算(需要较多 CPU 时间或者偏运算)的线程则设置较低的 优先级,确保处理器不会被独占。在不同的 JVM 以及操作系统上,线程规划会 存在差异,有些操作系统甚至会忽略对线程优先级的设定。
6、守护线程
Daemon(守护)线程是一种支持型线程,因为它主要被用作程序中后台调 度以及支持性工作。这意味着,当一个 Java 虚拟机中不存在非
Daemon 线程的 时候,Java 虚拟机将会退出。可以通过调用 Thread.setDaemon(true)将线程设置 为 Daemon 线程。我们一般用不上,比如垃圾回收线程就是 Daemon 线程。
Daemon 线程被用作完成支持性工作,但是在 Java 虚拟机退出时 Daemon 线 程中的 finally 块并不一定会执行。在构建 Daemon 线程时,不能依靠 finally 块中 的内容来确保执行关闭或清理资源的逻辑。
网友评论