对于线程终止,一般比较少的用到,那是因为线程执行完毕就会结束,但是有些情况下,有些后台线程会长时间在系统中运行,不会正常终结,本身就长期提供某个服务,那么如何关闭线程,就需要一种手段,在java中我们如何关闭线程呢?

  • 线程停止方法stop()

先看源码:

@Deprecated
public final void stop() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if (this != Thread.currentThread()) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
// A zero status value corresponds to "NEW", it can't change to
// not-NEW because we hold the lock.
if (threadStatus != 0) {
resume(); // Wake up thread if it was suspended; no-op otherwise
}

// The VM can handle all thread states
stop0(new ThreadDeath());
}

这个方法存在与Thread类中,从方法中可以看出已经打了@Deprecated,说明已经被废弃了,因为stop方法太过于暴力,stop是强行终止线程的,并且会释放所有的持有的锁,会引起数据不一致等问题。
举例:

/**
* Description:
*
* @Author lht
* @Date 2019/10/20 12:40 PM
**/
public class StopThreadUnsafe {

private static User u = new User();

public static class User {
private int id;
private String name;

public User() {
id = 0;
name = "0";
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}


public static class ChangeObjectThread extends Thread {
@Override
public void run() {
while (true) {
synchronized (u) {
int v = (int) (System.currentTimeMillis()/10000);
u.setId(v);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
u.setName(String.valueOf(v));
}
Thread.yield();
}

}
}

public static class ReadObjectThread extends Thread {
@Override
public void run() {
while (true) {
synchronized (u) {
if (u.getId() != Integer.parseInt(u.getName())) {
System.out.println(u.toString());
}
}
Thread.yield();
}
}
}

public static void main(String[] args) throws InterruptedException {
new ReadObjectThread().start();
while (true) {
Thread t = new ChangeObjectThread();
t.start();
Thread.sleep(150);
t.stop();
}
}
}

运行结果:

多线程-线程interrupt和stop方法_线程中断

id和name出现了不一致,因此除非你非常明白你的线程在做什么,否则stop方法没有你想的那么简单。
如果想要停止线程可以通过方法,自定义位置停止线程,代码如下:
代码:

public static class ChangeObjectThread extends Thread {
volatile boolean stop=false;

private void stopMe(){
stop=true;
}

@Override
public void run() {
while (true) {
if (stop){
System.out.println("exit by stop me");
break;
}
synchronized (u) {
int v = (int) (System.currentTimeMillis()/10000);
u.setId(v);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
u.setName(String.valueOf(v));
System.out.println(u.toString());
}
Thread.yield();
}

}
}


public static void main(String[] args) throws InterruptedException {
ChangeObjectThread changeObjectThread=new ChangeObjectThread();
changeObjectThread.start();
Thread.sleep(4000);
changeObjectThread.stopMe();
}
}
  • 线程停止方法interrupt,与stop方法不同
    准确来说interrupt是中断,线程中断是一种重要线程协作机制,中断就是让线程停止执行的意思,但是严格来讲,并不是使线程立即退出,而是给线程发送一个通知,告诉线程希望你退出,至于目标线程如何处理,则,完全由目标线程自己决定,这是跟stop方法的区别。
    由三个与线程中断有关的方法:
    public void Thread.interrupt(); //中断线程
    public boolean Thread.isInterrupted(); //判断是否被中断
    public static boolean Thread.interrupted();//判断是否被中断,并清除当前中断状态

Thread().interrupt()是一个实例方法,它是通知线程中断,也是设置中断标志位。
下面代码是对t1线程进行了中断,那么中断后t1会执行吗?

public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(){
@Override
public void run() {
while (true){
Thread.yield();
}
}
};
t1.start();
Thread.sleep(2000);
t1.interrupt();//不会中断
}

这里t1.interrupt()只是设置线程为中断状态,不会发生任何作用。如果希望退出就要增加中断处理代码:

public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(){
@Override
public void run() {
while (true){
if (Thread.currentThread().isInterrupted()){
System.out.println("interrupted");
break;
}
Thread.yield();
}
}
};
t1.start();
Thread.sleep(2000);
t1.interrupt();
}

加上中断处理代码后,判断是中断状态后立即退出线程即可。

如果在循环体中出现了像wait()和sleep()这样的方法只能通过中断来识别了。
sleep()方法会抛出一个中断异常,不是一个运行时异常,所以必须扑获它。
代码:

public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(){
@Override
public void run() {
while (true){
if (Thread.currentThread().isInterrupted()){
System.out.println("interrupted");
break;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Interrupted when sleep");
Thread.currentThread().interrupt();
}

Thread.yield();
}
}
};
t1.start();
Thread.sleep(3000);
t1.interrupt();
}

注意:Thread.sleep()方法由于中断而抛出异常,此时,它会清除中断标记,如果不加处理,那么下一次循环时,就无法扑获这个中断,故在异常处理中,再次设立中断标记位。