Java 终止(销毁)线程的方法(含完整示例)

sancaiodm Java 2021-12-28 1521 0

结束线程有以下三种方法:

(1)设置退出标志,通过外围改变标志位状态,使线程正常退出,也就是当run()方法完成后线程终止

(2)使用interrupt()方法中断线程

(3)使用stop方法强行终止线程(不推荐使用Thread.stop,此方法已经被废弃,使用它是不安全的,不在本文讨论范围以免更加混淆知识点)

----------------------------------------------------------------------------------------------------------------------

      首先要清楚java线程是一次性消费品,就是你任务执行完,线程也会自动终止并退出线程,并不需要我们主动去终止它。而我们所说的终止线程一般都指线程还未处理完任务,任务正在执行中,此时你决定放弃任务的继续执行,手动去终止线程的执行,如Runable的run方法中有一个while循环,或是run方法中有一个间隔定时循环任务,或是for循环等,此类线程循环在未满足停止条件前,它不会自动终止任务,此时如你放弃任务,则需要人为的去终止。下面简单说一下终止线程的两个有效方式,如有好的其它方法,大家可以留言分享!!!博主在此谢谢!

     1  标志位退出方式:在线程体设置标志位,此标志位可以线程外改变状态,每次循环都为判断此标志位是满足条件,否则终止任务,示例代码下如:

public class ShoujiOdmThread extends Thread {

	//volatile修饰符用来保证其它线程读取的总是该变量的最新的值,
	public volatile boolean exit = false; 
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
		while(!exit) {
		    try {
			    Thread.sleep(1000);
			    //此处模拟耗时任务,休眠1秒
			    System.out.println("shoujiodm.com");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		 System.out.println("线程结束了");
	}
}


// 需要终止线程处的使用
ShoujiOdmThread thread = new ShoujiOdmThread();
thread.exit = true;

示例二,线程池线程的终止

	static CountDownLatch  countDownLatch ;
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		countDownLatch = new CountDownLatch(1);
		try {
			Thread.sleep(100000);
			countDownLatch.countDown();  //此处主动终止定时循环任务
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
    
	public void start() {
		ScheduledExecutorService  schedule = Executors.newSingleThreadScheduledExecutor();
		final String jobname = "work";
		final Map<String,Future> futures = new Map<>();
		Future futureTask = schedule.scheduleAtFixedRate(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				//do your task here
				if(countDownLatch.getCount() == 0) {
					Future  future = futures.get(jobname);
					if(null != future) {
						future.cancel(true);
					}
				}
			}
			
		},30,30,TimeUnit.SECONDS);
		futures.put(jobname,futureTask);
		try {
			countDownLatch.await();
			schedule.shutdown();
		}catch(InterruptedException e) {
			e.printStackTrace();
		}
	}
}

2 使用interrupt方法终止线程

   我们先来看看含有interrupte的几个方法

   public boolean Thread.isInterrupted()             //判断是否被中断   (实例方法) 

   public static boolean Thread.interrupted()      //判断是否被中断,并清除当前中断状态  (静态方法)

  两个方法的源码:

    public boolean isInterrupted() {
        return interrupted;         //返回中断状态值
    }
    
    public static boolean interrupted() {
        Thread t = currentThread();
        boolean interrupted = t.interrupted;
        // We may have been interrupted the moment after we read the field,
        // so only clear the field if we saw that it was set and will return
        // true; otherwise we could lose an interrupt.
        if (interrupted) {//如果当前线程已是中断状态
            t.interrupted = false;   //将线程的中断状态改为false;
            clearInterruptEvent();
        }
        return interrupted;  //返回中断状态值
    }

       其他线程调用当前线程的interrupt方法时,即是线程设置一个标识,表示当前线程可以中断了,至于什么时候中断,取决于当前线程。调用 interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不是真的停止线程,而是通知目标线程,有人想要你终止。

    使用interrupt方法终止线程方式分两种情况:

    (1)当前线程处为阻塞状态,

        线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,sleep,join,wait方法是会抛出InterruptedException异常,我们在使用此三方法时也是需要去捕获InterruptedException异常的,

如下是Thread的sleep,join方法实现源码截图

image.png

image.png

如下Object类中的wait方法实现源码截图

image.png

    如果当前线程处于阻塞状态下,我们执行线程的interrupt方法,则线程会接收到一个中断异常(InterruptedException),从而终结被阻塞状态,我们可以在捕获中断异常后去终止该线程,

image.png

   

    (2)线程未处于阻塞状态

    使用上面interrupte 方式终止线程,只作用于那些因为执行了sleep、wait、join方法而阻塞的线程,使他们不再阻塞并同时会抛出InterruptedException异常,

    如果线程没有被阻塞,这时调用 interrupt()是不起作用,所以这方式需要用户自己去监视线程的状态为并做处理,似乎在实际的工作中很少遇到此种情况,据自己个人经验我们开启多线程都是一般为处理耗时任务,不会轻易去让线程进入阻塞状态,或是线程进入阻塞状态的时间尽量短,

示例代码如下:

public class StopThread {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ODMThread	thread = new ODMThread();
		thread.start();
		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		thread.interrupt();//调用interrupt 设置线程中断标识位
	}
	
	private static class ODMThread extends Thread{
		@Override
		public void run() {
			// TODO Auto-generated method stub
			super.run();
			//while循环方式 //判断是否被中断
			while(!isInterrupted()) {
				//只有当前线程可终止标识符为false时,才可进入while循环内执行业务
				//而线程的终止标识符是可以在线程体外改变的
				System.out.println("此处模拟耗时业务.......");
			}
			//for循环方式  //判断是否被中断
//			for(int index =0;index <=1000;index++) {
//				System.out.println("此处模拟耗时业务.......");
//				if(Thread.currentThread().isInterrupted()) {
//					//当前线程可终止标识被设置为true,则终止for循环
//					break;
//				}
//			}
			System.out.println("跳出while循环,终止线程");
		}
	}
}

这方式与前面说的使用标志位终止线程差不多

   


评论