Java线程中断与安全终止线程

stop() 终止线程--已过时被弃用,不要用

为什么弃用stop:

  1. 调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此不会保证线程的资源正常释放,通常是没有给予线程完成资源释放工作的机会,因此会导致程序可能工作在不确定状态。
  2. 调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。

理解中断interrupt()

interrupt() 方法仅仅是在当前线程中打一个停止的标记并不是真的停止线程

        也就是说,线程中断并不会立即终止线程,而是通知目标线程,有人希望你终止。至于目标线程收到通知后会如何处理,则完全由目标线程自行决定。这一点很重要,如果中断后,线程立即无条件退出,那么我们又会遇到 stop() 方法的老问题。

public void interrupt()

除非当前线程正在中断自身(通常允许这样做),否则将调用此线程的checkAccess方法,这可能会引发SecurityException。

  1. 如果该线程阻塞于调用Object类的wait(),wait(long)或wait(long,int)方法或该线程的join(),join(long),join(long,int),sleep(long)或sleep(long,int)方法时,则其中断状态将被清除,并将收到InterruptedException。
  2. 如果此线程阻塞于InterruptibleChannel上的I/O操作,则该通道channel将关闭,该线程的中断状态将被重置,并且该线程将收到ClosedByInterruptException。
  3. 如果此线程阻塞于一个Selector中,则该线程的中断状态将被重置,并且它将立即从选择操作中返回,可能具有非零值,就像调用选择器的唤醒方法wakeup()一样。
  4. 如果不是上面的任何一个条件,则将设置该线程的中断状态。

public static boolean interrupted()       

        测试当前线程是否已被中断。并清除线程的中断状态interrupted status。 换句话说,如果要连续两次调用此方法,则第二个调用将返回false(除非在第一个调用清除了其中断状态之后且在第二个调用对其进行检查之前,当前线程再次被中断)。

        一个线程在中断时处于未活动状态,其中断将被忽略,返回false。

public boolean isInterrupted()

        测试此线程是否已被中断。

程序示例,线程不同状态被中断时的中端状态

import java.util.concurrent.TimeUnit;
public class ThreadInterrupted {
	public static void main(String args[]) throws InterruptedException {
		// 构造线程
		// 正常线程--正常结束
		Thread normalThread = new Thread(new NormalRunner(), "NormalThread ");
		normalThread.setDaemon(true);

		// 一直slee的线程
		Thread sleepThread = new Thread(new SleepRunner(), "SleepThread");
		sleepThread.setDaemon(true);

		// 一直运行的线程
		Thread busyThread = new Thread(new BusyRunner(), "BusyThread");
		busyThread.setDaemon(true);
		// 启动线程
		normalThread.start();
		sleepThread.start();
		busyThread.start();
		// 休眠5秒,让线程充分运行
		TimeUnit.SECONDS.sleep(5);

		// 中断线程
		normalThread.interrupt();
		sleepThread.interrupt();
		busyThread.interrupt();

		System.out.println("NormalThread interrupted is " + normalThread.isInterrupted());
		System.out.println("SleepThread interrupted is " + sleepThread.isInterrupted());
		System.out.println("BusyThread interrupted is " + busyThread.isInterrupted());

		SleepUtils.second(2);
	}
	static class NormalRunner implements Runnable {
		@Override
		public void run() {
			System.out.println("NormalThread run");
		}
	}
	static class SleepRunner implements Runnable {
		@Override
		public void run() {
			while (true) {
				SleepUtils.second(10);
			}
		}
	}
	static class BusyRunner implements Runnable {
		@Override
		public void run() {
			while (true) {
			}
		}
	}
}

运行结果

NormalThread run
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:340)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
	at com.SleepUtils.second(SleepUtils.java:8)
	at com.ThreadInterrupted$SleepRunner.run(ThreadInterrupted.java:46)
	at java.lang.Thread.run(Thread.java:748)
NormalThread interrupted is false
SleepThread interrupted is false
BusyThread interrupted is true

程序示例,中断后程序不会马上停止运行 

public class ThreadInterrupt {
	public static void main(String args[]) throws InterruptedException {
		// 构造线程
		Thread normalThread = new Thread(new NormalRunner(), "normalThread");
		// 启动线程
		normalThread.start();
		TimeUnit.SECONDS.sleep(1);
		// 中断线程
		normalThread.interrupt();
		// 让main线程休眠10秒使normalThread线程能够充分运行
		TimeUnit.SECONDS.sleep(10);
	}

	static class NormalRunner implements Runnable {
		@Override
		public void run() {
			for (int i = 0; i <= 200000; i++) {
				System.out.println("i=" + i);
			}
			System.out.println("for loop end");
		}
	}
}

运行结果 

安全的终止线程

  • 使用中断方法interrupt()并结合isInterrupted()方法判断
  • 利用一个boolean变量来控制是否需要停止任务并终止该线程

程序示例

import java.util.concurrent.TimeUnit;
public class ThreadShutdown {
	public static void main(String args[]) throws InterruptedException {
		// 构造线程
		//方法一
        Thread oneThread = new Thread(new RunnerOne(), "RunnerOne");
		oneThread.start();
		// 休眠1秒,让线程充分运行
		TimeUnit.SECONDS.sleep(1);
		oneThread.interrupt();

        //方法二
		RunnerTwo twoRunner = new RunnerTwo();
		Thread twoThread = new Thread(twoRunner, "RunnerTwo");
		twoThread.start();
		TimeUnit.SECONDS.sleep(1);
		twoRunner.cancel();

		// 让main线程休眠10秒使normalThread线程能够充分运行
		TimeUnit.SECONDS.sleep(10);
	}
	static class RunnerOne implements Runnable {
		@Override
		public void run() {
			for (int i = 0; i <= 200000; i++) {
				if (!Thread.currentThread().isInterrupted()) {
					System.out.println("RunnerOne i=" + i);
				}
			}
		}
	}
	static class RunnerTwo implements Runnable {
		private volatile boolean on = true;
		@Override
		public void run() {
			for (int i = 0; i <= 200000; i++) {
				if (on) {
					System.out.println("RunnerTwo i=" + i);
				}
			}
		}
		public void cancel() {
			on = false;
		}
	}
}

运行结果

    

发布了243 篇原创文章 · 获赞 138 · 访问量 138万+

猜你喜欢

转载自blog.csdn.net/ystyaoshengting/article/details/104324150