java线程之停止线程

     在Java中有以下3种方法可以终止一个正在运行的线程:
     1、使用退出标志,是线程正常退出,也就是run方法完成后线程终止。
     2、使用stop方法强制终止线程,但不推荐使用这个方法,因为stop、suspend和resume一样,都是作废过期的方法。
     3、使用interrupt方法中断线程,大多数停止一个线程使用Thread.interrupt()方法,但是这个方法不会终止一个正在运行的线程,还需要加入一些判断才可以完成线程的停止。
下面我就用几个例子来介绍一下各种停止线程的效果。
一、停不了的线程——interrupt
本例子将调用interrupt()方法来停止线程,但是效果并不理想,并不能停止正在运行的线程,因为调用interrupt()方法仅仅是在当前线程中打了一个停止的标记,并不能真的停止线程。
	public static void main(String[] args) {
MyThread1 t = new MyThread1(); t.start(); try { Thread.sleep(2);
t.interrupted(); } catch (InterruptedException e) { System.out.println("main catch"); e.printStackTrace(); } } public static class MyThread1 extends Thread { @Override public void run() {
super.run(); for (int i = 0; i < 5000; i++) { System.out.println("i=" + (i + 1)); } } }

     运行结果我值截取了最后一段,控制台上正好输出到5000,说明调用interrupt方法并没有停止线程,运行结果如下:

              
           那么怎么才能停止线程呢?下面我回来介绍。

二、能停止的线程——异常法
      先看一个例子:
	public static void main(String[] args) throws InterruptedException {

		MyThread t = new MyThread();
		t.start();
		Thread.sleep(50);
		t.interrupt();
		System.out.println("end");
	}

	public static class MyThread extends Thread {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			super.run();
			for (int i = 0; i < 5000; i++) {
				if (this.interrupted()) {
					System.out.println("已经是停止状态了!我要退出了!");
					break;
				}

				System.out.println("i=" + (i + 1));
			}
			System.out.println("如果我被输出了,说明run方法还在继续执行,线程并未停止!");

		}
	}

       输出结果如下:

           

          从上面的结果可以看出来,这样写只是把for循环结束了,但是下面接着输出了“如果我被输出了,说明run方法还在继续执行,线程并未停止!”这句话,说明这样写并不能让run方法停止,所以这样写不可行。下面再来看一个例子。
	public static void main(String[] args) throws InterruptedException {

		MyThread t = new MyThread();
		t.start();
		Thread.sleep(50);
		t.interrupt();
		System.out.println("end");
	}

	public static class MyThread extends Thread {

		@Override
		public void run() {
			super.run();
			try {
				for (int i = 0; i < 5000; i++) {
					if (this.interrupted()) {
						System.out.println("已经是停止状态了!我要退出了!");
//异常法结束线程 throw new InterruptedException(); } System.out.println("i=" + (i + 1)); } System.out.println("我在for下面"); } catch (InterruptedException e) { System.out.println("进入Thread线程的run方法中的catch!"); e.printStackTrace(); } } }

      下面来看一下控制台上的输出结果:

          

         来分析一下结果,throw new InterruptedException()这句话下面的内容已经不会再执行了,因为“我在for下面”这句话并没有输出来,而是进入了catch,结束了整个run方法。所以异常方法来停止线程方法是靠谱的。
三、在沉睡中停止线程
        public static void main(String[] args) {

		try {
			MyThread t = new MyThread();
			t.start();
			Thread.sleep(200);
			t.interrupt();
		} catch (Exception e) {
			System.out.println("main catch");
			e.printStackTrace();
		}
		System.out.println("end!");

	}

	public static class MyThread extends Thread {

		@Override
		public void run() {

			super.run();
			try {
				System.out.println("run begin");
//为了确保能停止线程,这个休眠时间尽量长一点,如果时间太短,有可能主线程还没休眠结束呢,子线程就休眠结束了,这个线程也就正常运行了。 sleep(2000); System.out.println("run end"); } catch (Exception e) { System.out.println("在沉睡中被停止!进去catch!" + this.isInterrupted()); e.printStackTrace(); } } }
      运行结果如下:

           

          来分析一下结果,"run end"这句话没有输出,说明子线程里的sleep下面的内容再也不会执行了,而是进入到catch里面了,从而停止了run方法。说明这样写也是靠谱的。

四、能停止的线程——暴力停止

  使用stop()方法停止线程是非常暴力的行为,并且使用stop()方法会导致运行结果不一样,已经被官方文档废弃使用了。不使用的原因是不安全,假如当执行到stop方法时,子线程正在执行 synchronized里边的内容,那么不管

synchronized的方法有没有执行完,都会立刻停止这个线程,造成线程不安全。下面我来展示一个例子。

	public static void main(String[] args) {

		MyThread t = new MyThread();
		t.start();
		try {
Thread.sleep(9000); t.stop(); } catch (Exception e) { e.printStackTrace(); } } public static class MyThread extends Thread { private int i = 0; @Override public void run() { super.run(); while (true) { i++; System.out.println("i=" + i); try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
五、使用return停止线程
     将interrupt()和return结合也能实现停止线程的效果。但是建议使用抛异常停止线程,因为可以处理发生异常时候的相关信息。下面看一段代码。
       public static void main(String[] args) throws InterruptedException {

		MyThread t = new MyThread();
		t.start();
		Thread.sleep(2);
		t.interrupt();

	}

	public static class MyThread extends Thread {

		@Override
		public void run() {

			super.run();

			for (int i = 0; i < 5000; i++) {
				if (this.interrupted()) {
					System.out.println("已经是停止状态了!我要退出了!");
					return;
				}
				System.out.println("i=" + (i + 1));
			}

		}
	}

      下面看一下运行结果:

           

六、暂停线程
      暂停线程异味着此线程还可以恢复运行,在java中使用suspend()方法暂停线程,使用resume()方法恢复线程。不推荐suspend()和resume()方法,是因为容易造成死锁,比如执行suspend()这个方法的线程持有一个重要资源的锁,那么在没有执行恢复方法之前,是不会释放掉这个锁的,但是这个时候有另一个线程执行了resume()方法,但是这个线程恢复以后要想继续执行下去需要那个重要资源的锁,这个时候两个线程就造成死锁了
使用下面看一段代码。
	public static void main(String[] args) throws InterruptedException {

		MyThread t = new MyThread();
		t.start();
		//A段    暂停线程
		t.suspend();
		System.out.println("A="+System.currentTimeMillis() +"	"+"i="+t.getI());
		Thread.sleep(500);
		System.out.println("A="+System.currentTimeMillis() +"	"+"i="+t.getI());
		//B段    继续恢复
		t.resume();
		System.out.println("B="+System.currentTimeMillis() +"	"+"i="+t.getI());
		Thread.sleep(500);
		System.out.println("B="+System.currentTimeMillis() +"	"+"i="+t.getI());
		//C段    暂停线程
		t.suspend();
		System.out.println("C="+System.currentTimeMillis() +"	"+"i="+t.getI());
		Thread.sleep(500);
		System.out.println("C="+System.currentTimeMillis() + "	"+"i="+t.getI());
	}

	public static class MyThread extends Thread {

		private long i = 0;
		public long getI(){
			return i;
		}
		public void setI(long i){
			this.i=i;
		}
		@Override
		public void run() {
		
			super.run();
			while (true) {
				i++;
			}
		}
	}
  下面来分析一下运行结果:在A段中,先执行的是suspend()暂停线程的方法,所以从结果可以看出,系统的当前时间在变,但是i值确一直是0,说明线程没有在执行,仍是初始化的值,到了B段,执行了resume()恢复线程的方法,从结果也可以看出,当前系统的时间在变,i值也在改变,说面线程已经被恢复并在执行了,到了C段,出现这样的结果和A段原因是一样的。

      

以上我说了很多小例子,如果亲手敲一遍代码,看一下执行结果,会有更好的理解,毕竟线程执行的结果不是单一的。

   

 

 

    

      




原文地址:https://www.cnblogs.com/chentong/p/5614965.html