在Java中有以下三种方法可以终止正在运行的线程:
- 使用退出标志,使线程正常退出,也就是让run()方法运行完成后停止
- 使用stop方法强行终止线程,但是不推荐使用这个方法,因为stop是作废过期的方法,使用它可能产生不可预料的结果
- 使用interrupt方法中断线程
下面分别看一下三种用法的区别:
1.使用退出标志让线程正常退出
package chapter1;
public class MyThread extends Thread{
private long i=0;
private volatile boolean isRunning = true;
@Override
public void run(){
while(isRunning){
i++;
System.out.println(i);
}
}
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
Thread.sleep(1000);
t.isRunning=false;
System.out.println("main end");
}
}
控制台输出如下,可以看到在主线程中修改标记的值,使while循环停止,可以让线程t正常退出,推荐使用这种方法
184908
184909
184910
184911
184912
184913
184914
184915
main end
2.使用stop方法强制停止线程
package chapter1;
public class MyThread extends Thread{
private long i=0;
@Override
public void run(){
while(true){
i++;
System.out.println(i);
}
}
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
Thread.sleep(1000);
t.stop();
System.out.println("main end");
}
}
执行main方法,可以在控制台看到如下输出,也可以完成线程的停止。
181458
181459
181460
181461
181462
181463
181464
181465
181466
181467
main end
既然stop方法可以完成线程的停止,为什么jdk要废弃掉这个方法,不建议使用呢?我们看一下下面这个例子:
首先创建一个用户类,里面有一个同步方法updateUser,为了便于观察,模拟程序的执行时间,在两次set中间休眠了1秒
package chapter1;
public class User {
private String username;
private String password;
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;
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
synchronized public void updateUser(String u,String p){
try {
this.setUsername(u);
Thread.sleep(1000);
this.setPassword(p);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
接下来在主线程中我们执行0.5秒以后使用stop方法强制停止这个线程,观察执行结果
package chapter1;
public class MyThread extends Thread{
private User user;
public MyThread(User user) {
super();
this.user = user;
}
@Override
public void run(){
user.updateUser("b", "bb");
}
public static void main(String[] args) throws InterruptedException {
User a = new User("a","aa");
Thread t = new MyThread(a);
t.start();
t.sleep(500);
t.stop();
System.out.println("username:"+a.getUsername()+" password:"+a.getPassword());
}
}
控制台输出结果如下:
username:b password:aa
使用stop方法会强制停止线程,不管当前线程在干什么都会被停止,使用stop暴力释放锁可能会导致数据不一致的问题。
3.使用interrupt方法来停止线程
interrupt方法并不会真的停止线程,只是对线程做一个标记,标记这个线程被中断了,所以需要和return或者抛异常的方法结合来使用。
package chapter1;
public class MyThread extends Thread{
private volatile long i=0;
@Override
public void run(){
try {
while(true){
i++;
System.out.println(i);
if(this.interrupted()){
// throw new InterruptedException();
return;
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
MyThread t = new MyThread();
t.start();
Thread.sleep(1000);
t.interrupt();
System.out.println("main end");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
其实第一种和第三种方式是类似的,都是通过标记判断线程是否终止,然后使用return 或者throw a exception的方式来结束线程的执行,只不过interrupt不需要我们来定义标记。第二种方式使用stop方法太过于暴力,如果程序在执行一些很关键的操作,被强行终止,可能会发现意向不到的结果,最好还是不要使用。