start 方法中有一个函数调用: os::start_thread(thread); ,调用平台启动线程的方法,最终会调用 Thread.cpp 文件中的 JavaThread::run() 方法
3.2 线程的终止 3.2.1 通过标记位来终止线程
正常我们线程内的东西都是循环执行的,那么我们实际需求中肯定也存在想在其他线程来停止当前线程的需要,这是后我们可以通过标记位来实现,所谓的标记为其实就是 volatile 修饰的变量,着由它的可见性特性决定的,如下代码就是依据 volatile 来实现标记位停止线程
//定义标记为 使用 volatile 修饰 private static volatile boolean mark = false; @Test public void markTest(){ new Thread(() -> { //判断标记位来确定是否继续进行 while (!mark){ try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程执行内容中..."); } }).start(); System.out.println("这是主线程走起..."); try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } //10秒后将标记为设置 true 对线程可见。用volatile 修饰 mark = true; System.out.println("标记位修改为:"+mark); } 3.2.2 通过 stop 来终止线程我们通过查看 Thread 类或者 JDK API 可以看到关于线程的停止提供了 stop() , supend() , resume() 等方法,但是我们可以看到这些方法都被标记了 @Deprecated 也就是过时的,
虽然这几个方法都可以用来停止一个正在运行的线程,但是这些方法都是不安全的,都已经被抛弃使用,所以在我们开发中我们要避免使用这些方法,关于这些方法为什么被抛弃以及导致的问题 JDK 文档中较为详细的描述 《Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated?》
在其中有这样的描述:
总的来说就是:
调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 等语句中的内容,并抛出 ThreadDeath 异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些工作的得不到完成,如文件,数据库等的关闭。
调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。
3.2.3 通过 interrupt 来终止线程通过上面阐述,我们知道了使用 stop 方法是不推荐的,那么我们用什么来更好的停止线程,这里就引出了 interrupt 方法,我们通过调用 interrupt 来中断线程
当其他线程通过调用当前线程的 interrupt 方法,表示向当前线程打个招呼,告诉他可以中断线程的执行了,至于什么时候中断,取决于当前线程自己
线程通过检查自身是否被中断来进行相应,可以通过 isInterrupted() 来判断是否被中断。
我们来看下面代码:
打印结果如下:
上述代码中我们可以看到,我们创建了 interrupt-1 线程,其中用 interrupt 来判断当前线程是否处于中断状态,如果处于中断状态那么就自然结束线程,这里的结束的具体操作由我们开发者来决定。再创建 interrupt-2 线程,代码相对简单不阐述,当执行到某时刻时将线程 interrupt-1 设置为中断状态,也就是通知 interrupt-1 线程。
线程中断标记复位 :