Java多线程之停止线程

打申请一个多星期了,流程也走的差不多了,离开的日子越来越近了    即将离开呆了两年的地方,的确有点舍不得,但毕竟是走到这一步了   一定要做出决定的。一年多了,一直在做增删改查。技术却没什么实质性的提高,  一直想搞点底层的东西,也被多线程,线程池,连接池坑了好多次,于是准备好好研究下这块,多线程一直让我胆怯的东西,虽然一直想攻克这块,但是却也一直想走捷径,到头来发现没有捷径可走。所以慢慢啃喽


最近在看Java多线程编程核心技术,也一直忘的比看的快,所以就做个笔记吧,概念性的东西就懒得提了



~~~~~~~~~~~~~~~~~~~~~~~~~~~

停止一个线程意味着在线程处理完任务之前停掉正在做的操作,也就是放弃当前的操作.

停止一个线程可以使用Thread.stop()方法,但是最好不要用它,虽然确实可以停止一个正在运行的线程,但是这个方式是不安全的并且被废弃的


大多数停止一个线程的操作使用Thread.interrupt()方法,尽管方法的名称是"停止、终止"的意思,但这个方法不会终止一个正在运行的线程,还需要加入一个判断才可以完成线程的停止.


在Java中有以下3种方法可以终止正在运行的线程:

扫描二维码关注公众号,回复: 934693 查看本文章

1.使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。

2.使用stop方法强制终止线程,但是不推荐,因为stop和suspend及resume一样都是过期的方法,会产生不可预料的结果.

3. 使用interrupt方法中断线程


停止不了的线程

调用interrupt方法来停止线程,但是interrupt方法的效果并不想for+break那样马上停止循环,调用interrupt方法仅仅是在当前的线程中打了一个停止的标记,并不能真正的停止线程

public class MyThread extends Thread {
    @Override
	public void run() {
		super.run();
		for (int i = 0; i < 500000; i++) {
			System.out.println("i=" + (i + 1));
		}
	}
}
public class Main {

	public static void main(String[] args) {
        try {
			MyThread thread = new MyThread();
			thread.start();
			Thread.sleep(2000);
			thread.interrupt();
		} catch (InterruptedException e) {
			System.out.println("main catch");
			e.printStackTrace();
		}
	}

}
从运行结果上看,调用interrupt方法并没有停止线程。如何停止线程呢?


判断线程是否停止

如何判断线程的状态是不是停止的,在Java API中,Thread类提供了两种方法.

1. this.interrupted(): 测试当前线程是否已经中断。

public static boolean interrupted() {
        return currentThread().isInterrupted(true);
}

2. this.isInterrupted(): 测试线程是否已经中断

public boolean isInterrupted() {
        return isInterrupted(false);
}

两个都调用的是一个底层的 native的方法

private native boolean isInterrupted(boolean ClearInterrupted);


native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。


那么这两个方法有什么区别呢? 先来看看this.interrupted()方法的解释:测试当前线程是否已经中断,当前线程是指运行this.interruped()方法的线程

public class MyThread extends Thread {
	@Override
	public void run() {
		super.run();
		for (int i = 0; i < 500000; i++) {
			System.out.println("i=" + (i + 1));
		}
	}
}

public class Main {
	public static void main(String[] args) {
		try {
			MyThread thread = new MyThread();
			thread.start();
			Thread.sleep(1000);
			thread.interrupt();
			//Thread.currentThread().interrupt();
			System.out.println("是否停止1?="+thread.interrupted());
			System.out.println("是否停止2?="+thread.interrupted());
		} catch (InterruptedException e) {
			System.out.println("main catch");
			e.printStackTrace();
		}
		System.out.println("end!");
	}
}

程序运行结果如下所示:


从控制台打印结果来看,线程并未停止,这也就证明的interrupted方法的解释,测试当前线程是否已经中断,这个当前线程是main,它从未中断过,所以结果是两个false

如何使main线程产生中断效果呢?

public class Main2 {
    public static void main(String[] args) {
		Thread.currentThread().interrupt();
		System.out.println("是否停止1?=" + Thread.interrupted());
		System.out.println("是否停止2?=" + Thread.interrupted());
		System.out.println("end!");
	}
}

结果:


从上述结果来看,方法interrupted()的确判断出当前线程是否是停止状态,但为什么第二个值是false呢?官方文档对interrupted方法的解释:

测试当前线程是否已经中断。线程的中断状态由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。


文档已经解释得很详细,interrupted()方法具有清除状态的功能,所以第2次调用interrupted()方法返回的值是false。文档已经解释得很详细,interrupted()方法具有清除状态的功能,所以第2次调用interrupted()方法返回的值是false。


介绍完interrupted()方法后再来看一下isInterrupted()方法,声明如下:介绍完interrupted()方法后再来看一下isInterrupted()方法

public class Main3 {
    public static void main(String[] args) {
		try {
			MyThread thread = new MyThread();
			thread.start();
			Thread.sleep(1000);
			thread.interrupt();
			System.out.println("是否停止1?="+thread.isInterrupted());
			System.out.println("是否停止2?="+thread.isInterrupted());
		} catch (InterruptedException e) {
			System.out.println("main catch");
			e.printStackTrace();
		}
		System.out.println("end!");
	}
}

运行结果如下:



从结果中可以看到,方法isInterrupted()并未清除撞他标志,所以打印了两个true.

最后,再来看一下这两个方法的解释。

1. this.interrupted():测试当前线程是否已经中断状态,执行后具有将状态标志清除为false的功能。

2. this.isInterrupted():测试线程Thread对象是否已经是中断状态,但不清除状态标志.


能停止的线程-异常法

public class MyThread extends Thread {
	@Override
	public void run() {
		super.run();
		for (int i = 0; i < 500000; i++) {
			if (this.interrupted()) {
				System.out.println("已经是停止状态了!我要退出了!");
				break;
			}
			System.out.println("i=" + (i + 1));
		}
	}
}
public class Run {

	public static void main(String[] args) {
		try {
			MyThread thread = new MyThread();
			thread.start();
			Thread.sleep(2000);
			thread.interrupt();
		} catch (InterruptedException e) {
			System.out.println("main catch");
			e.printStackTrace();
		}
		System.out.println("end!");
	}

}


上面的实例虽然UI出了线程,但是for语句下面还有语句的话,还是会继续执行
public class MyThread extends Thread {
	@Override
	public void run() {
		super.run();
		for (int i = 0; i < 500000; i++) {
			if (this.interrupted()) {
				System.out.println("已经是停止状态了!我要退出了!");
				break;
			}
			System.out.println("i=" + (i + 1));
		}
		System.out.println("我被输出,如果此代码是for又继续运行,线程并未停止!");
	}
}
public class Run {

	public static void main(String[] args) {
		try {
			MyThread thread = new MyThread();
			thread.start();
			Thread.sleep(2000);
			thread.interrupt();
		} catch (InterruptedException e) {
			System.out.println("main catch");
			e.printStackTrace();
		}
		System.out.println("end!");
	}

}


该怎么解决语句继续运行的问题呢?
public class MyThread extends Thread {
	@Override
	public void run() {
		super.run();
		try {
			for (int i = 0; i < 500000; 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("进MyThread.java类run方法中的catch了!");
			e.printStackTrace();
		}
	}
}



在沉睡中停止

public class MyThread extends Thread {
	@Override
	public void run() {
		super.run();
		try {
			System.out.println("run begin");
			Thread.sleep(200000);
			System.out.println("run end");
		} catch (InterruptedException e) {
			System.out.println("在沉睡中被停止!进入catch!"+this.isInterrupted());
			e.printStackTrace();
		}
	}
}

public class Run {

	public static void main(String[] args) {
        try {
			MyThread thread = new MyThread();
			thread.start();
			Thread.sleep(200);
			thread.interrupt();
		} catch (InterruptedException e) {
			System.out.println("main catch");
			e.printStackTrace();
		}
		System.out.println("end!");
	}

}



如果在sleep状态下停止某一线程,会进入catch语句块,并且清除停止状态值,使之变成false
前一个实验是先sleep然后再用interrupt()停止,与之相反的操作也要注意


public class MyThread extends Thread {
	@Override
	public void run() {
		super.run();
		try {
			for(int i=0;i<100000;i++){
				System.out.println("i="+(i+1));
			}
			System.out.println("run begin");
			Thread.sleep(200000);
			System.out.println("run end");
		} catch (InterruptedException e) {
			System.out.println("先停止,再遇到了sleep!进入catch!");
			e.printStackTrace();
		}
	}
}

public class Run {
	public static void main(String[] args) {
		MyThread thread = new MyThread();
		thread.start();
		thread.interrupt();
		System.out.println("end!");
	}
}


能停止的线程-暴力停止

public class MyThread extends Thread {
	private int i = 0;

	@Override
	public void run() {
		try {
			while (true) {
				i++;
				System.out.println("i=" + i);
				Thread.sleep(1000);
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

public class Run {

	public static void main(String[] args) {
		try {
			MyThread thread = new MyThread();
			thread.start();
			Thread.sleep(8000);
			thread.stop();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}


使用return停止线程


使用interrupt()与return结合使用也能实现线程停止的效果
public class MyThread extends Thread {

	@Override
	public void run() {
			while (true) {
				if (this.isInterrupted()) {
					System.out.println("停止了...");
					return;
				}
				System.out.println("timer=" + System.currentTimeMillis());
			}
	}

}


public class Run {

	public static void main(String[] args) throws InterruptedException {
		MyThread t=new MyThread();
		t.start();
		Thread.sleep(2000);
		t.interrupt();
	}

}



不过还是建议使用 抛异常 的方式来实现线程的停止,因为在catch块中可以对异常信息进行相关的处理,而且使用异常能更好的 更方便的控制程序的运行流程,不至于代码中出现很多个return;造成污染


猜你喜欢

转载自blog.csdn.net/yuchao2015/article/details/78742154