1.停止线程
有三种方法可以终止正在运行的线程
1)使用退出标志,使线程运行run正常退出
2)使用stop(),但不推荐,他和suspend和resume一样,都是作废的方法
3)使用interrupt方法中断线程
使用java内置支持多线程的类设计多线程应用是很常见的事情,然而处理不好就会导致超出预期的·行为并且难以定位错误
1.1 停止不了的线程
package mythread;
public class Thread3 extends Thread{
public void run(){
super.run();
for (int i = 0; i < 500000; i++) {
System.out.println("i="+(i+1));
}
}
}
package mythread;
public class run3 {
public static void main(String[] args) {
try {
Thread3 t3=new Thread3();
t3.start();
Thread.sleep(2000);
t3.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
}
}
结果
i=499983
i=499984
i=499985
i=499986
i=499987
i=499988
i=499989
i=499990
i=499991
i=499992
i=499993
i=499994
i=499995
i=499996
i=499997
i=499998
i=499999
i=500000
注:调用intertupt()方法仅仅是在当前线程中打了一个停止的标记,并不是真正的停止线程;
1.2 判断线程是否是停止状态
1)this.interrupted();测试当前线程是否已经中断
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
2)this.isInterrupted():判断线程是否已经中断
public boolean isInterrupted() {
return isInterrupted(false);
}
修改上面测试代码
package mythread;
public class run3 {
public static void main(String[] args) {
try {
Thread3 t3=new Thread3();
t3.start();
Thread.sleep(2000);
t3.interrupt();
System.out.println("是否停止1 "+t3.interrupted());
System.out.println("是否停止2 "+t3.interrupted());
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
}
}
结果
i=994
i=995
i=996
i=997
i=998
i=999
i=1000
是否停止1 false
是否停止2 false
测试当前线程是否中断,这个当前线程是main,从未中断,所以输出false;
现在停止main线程
package mythread;
public class run3 {
public static void main(String[] args) {
// Thread3 t3=new Thread3();
// t3.start();
// Thread.sleep(2000);
// t3.interrupt();
Thread.currentThread().interrupt();
System.out.println("是否停止1 "+Thread.interrupted());
System.out.println("是否停止2 "+Thread.interrupted());
}
}
结果:
是否停止1 true
是否停止2 false
注:interrupted()是测试当前线程是否中断,并清除线程的中断状态
isInterrupted()
测试线程Thread对象是否已经是中断状态,但不清除状态标记;
1.3 能停止的线程---异常法
package mythread;
public class Thread3 extends Thread{
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("end");
}
}
package mythread;
public class run3 {
public static void main(String[] args) {
try {
Thread3 t3=new Thread3();
t3.start();
Thread.sleep(2000);
t3.interrupt();
//Thread.currentThread().interrupt();
// System.out.println("是否停止1 "+Thread.interrupted());
// System.out.println("是否停止2 "+Thread.interrupted());
// System.out.println("是否停止1 "+t3.isInterrupted());
// System.out.println("是否停止2 "+t3.isInterrupted());
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
}
}
结果
i=263345
i=263346
i=263347
线程中断退出
end
注:线程输出end说明线程并没有停止,修改线程run方法
package mythread;
public class Thread3 extends Thread{
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("end");
} catch (InterruptedException e) {
System.out.println("进入run catch");
e.printStackTrace();
}
}
}
输出结果:
i=277141
线程中断退出
进入run catch
java.lang.InterruptedException
at mythread.Thread3.run(Thread3.java:11)
1.4 在沉睡中停止
package mythread;
public class Thread4 extends Thread{
public void run(){
try {
System.out.println("run begin");
Thread.sleep(20000);
} catch (InterruptedException e) {
System.out.println("在沉睡中终止会进入catch "+this.isInterrupted());
e.printStackTrace();
}
}
}
package mythread;
public class run4 {
public static void main(String[] args) {
try {
Thread4 t4=new Thread4();
t4.start();
Thread.sleep(200);
t4.interrupt();
} catch (InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("main end");
}
}
结果:
run begin
main end
在沉睡中终止会进入catch false
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at mythread.Thread4.run(Thread4.java:7)
注:如果在sleep状态下停止某一线程,会进入catch里面去,并清除停止状态值。
与之相反,先停止再sleep也会进入catch里去,并清除停止状态值;
1.5 能停止的线程---暴力停止
package stopMethod;
public class Thread1 extends Thread{
private int i=0;
public void run(){
try {
while(true){
i++;
System.out.println(i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package stopMethod;
public class Run1 {
public static void main(String[] args) {
try {
Thread1 t1=new Thread1();
t1.start();
Thread.sleep(8000);
t1.stop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
结果
1
2
3
4
5
6
7
8
1.6 方法stop()与java.lang.ThreadDeath异常
调用stop会跑出java.lang.ThreadDeath,但通常情况下,此异常不需要显示的捕捉
package stopMethod;
public class Thread2 extends Thread{
public void run(){
try{
this.stop();
}catch(ThreadDeath e){
System.out.println("进入stop catch里面去了");
e.printStackTrace();
}
}
}
package stopMethod;
public class Run2 {
public static void main(String[] args) {
Thread2 t2=new Thread2();
t2.start();
}
}
结果:
进入stop catch里面去了
java.lang.ThreadDeath
at java.lang.Thread.stop(Thread.java:813)
at stopMethod.Thread2.run(Thread2.java:6)
注:方法stop已经作废,如果强制让线程停止则可能使一些清理性的工作得不到完成,
另外一个情况就是对锁定的对象进行“解锁”,导致数据得不到同步的处理,出现数据不一致的情况。
1.7 释放锁的不良后果
package stopMethod;
public class SynchronizedObject {
private String username="a";
private String password="aa";
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
synchronized public void printObject(String name,String pwd){
try {
this.username=name;
Thread.sleep(10000);
this.password=pwd;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package stopMethod;
public class Thread3 extends Thread{
private SynchronizedObject object;
public Thread3(SynchronizedObject object){
super();
this.object=object;
}
public void run(){
object.printObject("b", "bb");
}
}
package stopMethod;
public class Run3 {
public static void main(String[] args) {
try {
SynchronizedObject object=new SynchronizedObject();
Thread3 t3=new Thread3(object);
t3.start();
Thread.sleep(200);
t3.stop();
System.out.println(object.getUsername()+" "+object.getPassword());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出结果:
b aa
注:使用stop()释放锁会给数据造成不一致性的结果,如果出现这样额结果,陈旭处理的结果就有可能遭到破坏,最终导致程序执行流程出错,
该方法已经在jdk中作废,显然它在功能上有缺陷。
1.8 使用return停止线程
将方法interrupt与return结合使用也能实现停止线程的效果
package stopMethod;
public class Thread4 extends Thread{
public void run(){
while(true){
if(this.isInterrupted()){
System.out.println("停止了。。");
return;
}
System.out.println(System.currentTimeMillis());
}
}
}
package stopMethod;
public class Run4 {
public static void main(String[] args) {
try {
Thread4 t4=new Thread4();
t4.start();
Thread.sleep(1000);
t4.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出结果:
1473999594715
1473999594715
1473999594715
1473999594715
停止了。。
注:不过还是建议使用“抛异常”的方法来停止线程。因为在catch块中可以对异常的信息进行相关的处理,而且使用异常能更好的更方便控制流程的运行流程,
不至于代码中出现多个return,造成污染。