面试官:如何停止一个正在运行的线程

停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作。停止一个线程可以用Thread.stop() 方法。

使用 stop 方法中止线程

public class ThreadTest{

	 static class Thread1 extends Thread {
	        @Override
	        public void run() {
	            for (int i = 0; i < 500000; i++) {
	                System.out.println("打印的数字"+i);
	            }
	        }
	 }
	public static void main(String[] args) throws InterruptedException {
		Thread1 thread1 = new Thread1();
		thread1.start();
        //保证子线程进入运行状态,避免还没运行就被终止
        Thread.sleep(100);
        //暴力停止子线程
        thread1.stop();
	}

}

输出结果如下:
在这里插入图片描述

可以看得出,线程确实被终止了。但最好不要用它。虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且是已被废弃的方法。

在这里插入图片描述
这里面的解释就是:

Stop 方法时被废弃掉的方法,不推荐使用,使用 Stop 方法,会一直向上传播 ThreadDeath 异常,从而使得目标线程解锁所有锁住的监视器,即释放掉所有的对象锁。使得之前被锁住的对象得不到同步的处理,因此可能会造成数据不一致的问题。注释中建议我们取代 Stop 方法,可以增加一个变量。目标线程周期性地检查这个变量。如果变量在某个时间指示线程终止,则目标线程将以有序的方式从 run 方法中返回。当然,如果目标线程长时间进行等待,则可以使用中断的方式来终止线程。

使用退出标志终止线程

通过指定一个条件变量,线程可以控制该变量,内部线程在内部循环检查该变量。

public class ThreadTest extends Thread {

	    public volatile boolean exit = false; 

	    public void run() { 
	        while (!exit); 
	    } 
	public static void main(String[] args) throws InterruptedException {
		ThreadTest thread = new ThreadTest(); 
        thread.start(); 
        Thread.sleep(5000); // 主线程延迟5秒 
        thread.exit = true;  // 终止线程thread 
        thread.join(); 
        System.out.println("线程退出!"); 
	}

}

在上面代码中定义了一个退出标志 exit,当 exit 为 true 时,while 循环退出,exit 的默认值为 false,在定义 exit 时,使用了 Java 关键字 volatile,这个关键字可以是 exit 同步,也就是说在同一时刻只能由一个线程来修改 exit 的值, 可以参考我的另外一篇文章: volatile底层实现原理详解

使用 interrupt 方法终止线程

public class ThreadTest extends Thread {

	   private boolean flag = true;

	    @Override
	    public void run() {
	        while (flag) {
	            synchronized (this) {

	                try {
	                    sleep(10000);
	                } catch (InterruptedException e) {
	                    e.printStackTrace();
	                    this.stopThread();
	                }
	            }
	        }
	    }

	    public void stopThread() {
	        System.out.println("线程已经退出。。。");
	        this.flag = false;
	    }
	public static void main(String[] args) throws InterruptedException {
		    ThreadTest threadTest = new ThreadTest();
		    threadTest.start();
	        System.out.println("线程开始");
	        try {
	            Thread.sleep(5000);
	        } catch (InterruptedException e) {
	            e.printStackTrace();
	        }
	        threadTest.interrupt();
	}

}

interrupt 方法用来设置线程的中断状态,如果目标线程正阻塞于 wait、sleep 等方法时,首先会清除目前线程的中断状态,然后抛出 java.lang.InterruptedException异常

在这里插入图片描述

使用 Thread.isInterrupted() 终止线程

public class ThreadTest extends Thread {
	 int count=0;
	   public void run(){
	       System.out.println(getName()+"将要运行...");
	       while(!this.isInterrupted()){
	           System.out.println(getName()+"运行中"+count++);
	           try{
	               Thread.sleep(400);
	           }catch(InterruptedException e){
	               System.out.println(getName()+"从阻塞中退出...");
	               System.out.println("this.isInterrupted()="+this.isInterrupted());

	           }
	       }
	       System.out.println(getName()+"已经终止!");
	   }
	public static void main(String[] args) throws InterruptedException {
		ThreadTest ta=new ThreadTest();
	        ta.setName("ThreadA");
	        ta.start();
	        Thread.sleep(2000);
	        System.out.println(ta.getName()+"正在被中断...");
	        ta.interrupt();
	        System.out.println("ta.isInterrupted()="+ta.isInterrupted());

	}

}

在这里插入图片描述
什么情况,打断了为什么还能继续输出?

上面已经说过:interrupt 方法用来设置线程的中断状态,如果目标线程正阻塞于 wait、sleep 等方法时,首先会清除目前线程的中断状态,然后抛出 java.lang.InterruptedException异常

目标线程正在进行第 4 次循环,进入了 sleep 操作中,此时收到了主线程的 interrupt 操作,目标线程拥有了中断状态,则先清除中断状态,然后抛出异常,若是 catch 语句没有处理异常,则下一 次循环中 isInterrupted() 为false,线程会继续执行,可能 N 次抛出异常,也没法让线程中止。

那怎么停止当前线程呢?在线程同步的时候要有一个叫 二次惰性检测,能在提升效率的基础上又确保线程真正中同步控制中。那么把线程正确退出的方法称为 “双重安全退出”,不是以 isInterrupted () 为循环条件。而以一个标记做为循环条件。

public class ThreadTest extends Thread {
	private boolean isInterrupted=false;
	   int count=0;
	   
	   public void interrupt(){
	       isInterrupted = true;
	       super.interrupt();
	      }
	   
	   public void run(){
	       System.out.println(getName()+"将要运行...");
	       while(!isInterrupted){
	           System.out.println(getName()+"运行中"+count++);
	           try{
	               Thread.sleep(400);
	           }catch(InterruptedException e){
	               System.out.println(getName()+"从阻塞中退出...");
	               System.out.println("this.isInterrupted()="+this.isInterrupted());

	           }
	       }
	       System.out.println(getName()+"已经终止!");
	   }
	public static void main(String[] args) throws InterruptedException {
		ThreadTest ta=new ThreadTest();
	        ta.setName("ThreadA");
	        ta.start();
	        Thread.sleep(2000);
	        System.out.println(ta.getName()+"正在被中断...");
	        ta.interrupt();
	        System.out.println("ta.isInterrupted()="+ta.isInterrupted());

	}

}

执行结果如下:
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,那我就开始对你进行Java面试了。 1. 讲一下Java中的多态性是什么? Java中的多态性指的是不同的对象可以对同一消息做出不同的响应。Java实现多态性的方式有两种:方法重载和方法重写。方法重载指的是在同一个类中定义多个方法,这些方法具有相同的名字,但是参数列表不同。方法重写指的是在子类中重新定义父类中已经定义的方法,使得子类对象可以对该方法做出不同的响应。 2. 说一下Java中的异常处理机制? Java中的异常处理机制是通过try-catch-finally语句块来实现的。当有异常产生时,程序会跳转到对应的catch块进行处理,如果catch块中没有处理该异常的代码,则会抛出该异常给上层调用者处理。finally块中的代码会在try-catch块中的代码执行完毕后执行,无论是否有异常产生。 3. 什么是Java中的垃圾回收机制? Java中的垃圾回收机制指的是自动回收不再被使用的对象所占用的内存空间。Java中的垃圾回收机制通过JVM来实现,JVM会定期扫描程序中的对象,找出不再被引用的对象并释放它们占用的内存空间。Java中的垃圾回收机制可以提高程序的运行效率和可靠性,但也会占用一定的系统资源。 4. 什么是Java中的反射? Java中的反射指的是在程序运行时动态获取对象的信息和操作对象的属性和方法。Java中的反射机制可以使得程序在运行时动态创建对象、调用方法和修改属性等,可以提高程序的灵活性和可扩展性。但是Java中的反射机制会降低程序的运行效率,并且容易破坏程序的封装性和安全性。 5. 请简述Java中的线程同步机制? Java中的线程同步机制指的是通过同步锁来实现多个线程对共享资源的互斥访问。Java中的同步锁可以通过synchronized关键字来实现,也可以通过Lock接口的实现类来实现。当一个线程获取了同步锁后,其他线程必须等待该线程释放锁后才能继续访问共享资源。Java中的线程同步机制可以保证共享资源的正确性和可靠性,但也会降低程序的并发性能和响应速度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值