3种方法


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



1 )使用退出标志使线程正常退出。

2 )使用 stop()方法强行终止线程,但是这个 方法不推荐使用,因为 stop() 和 suspend() 、

      resume()一样,都是作废过期的方法,使用它们可 能发生不可预料的结果。

3 )使用 interrupt() 方法中断线程。


调用interrupt()方法来停止线程

但interrupt() 方法的使用效果并不像 for+break语句那样,马上就停止循环。调用 interrupt()方法仅仅是在当前线程中做了一个停止 的标记,并不是真正停止线程。

文件MyThread.java代码

package test1_11;

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

 

运行类Run.java代码

package test1_11;

public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread thread = new MyThread();
        thread.start();
        Thread.sleep(20);
        thread.interrupt();
        System.out.println("zzzzzzzzzzzzzzzzzzzzzzz");
    }
}

运行结果  

java线程超时后解除等待 java线程停止的几种方法_开发语言

 

在 4357 行处输出了 zzzzzzzz ,说明 sleep 时间为20ms 时, for 语句执行了 4357 次循环



从运行结果来看,调用 interrupt()方法并没有将线程停 止,那如何停止线程呢?


判断线程是否为停止状态

Thread.java 类提供了两个判断方法

1 ) public static boolean interrupted():测试 currentThread() 是否已经中断。

/**     * Tests whether the current thread has been interrupted.  The
     * <i>interrupted status</i> of the thread is cleared by this method.  In
     * other words, if this method were to be called twice in succession, the
     * second call would return false (unless the current thread were
     * interrupted again, after the first call had cleared its interrupted
     * status and before the second call had examined it).
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  <code>true</code> if the current thread has been interrupted;
     *          <code>false</code> otherwise.
     * @see #isInterrupted()
     * @revised 6.0
     */
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

2)public boolean this.isInterrupted():测试this关键 字所在类的对象是否已经中断。

/**     * Tests whether this thread has been interrupted.  The <i>interrupted
     * status</i> of the thread is unaffected by this method.
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  <code>true</code> if this thread has been interrupted;
     *          <code>false</code> otherwise.
     * @see     #interrupted()
     * @revised 6.0
     */
    public boolean isInterrupted() {
        return isInterrupted(false);
    }

    /**
     * Tests if some Thread has been interrupted.  The interrupted state
     * is reset or not based on the value of ClearInterrupted that is
     * passed.
     */
    private native boolean isInterrupted(boolean ClearInterrupted);


这两个方法可以判断线程是否是停止状态,那么这 两个方法有什么区别呢?



先来看看方法this.interrupted() 方法的解释


测试当前线程是否已经中断,当前线程是 指运行 this.interrupted() 方法的线程。


类MyThread.java 代码

package test1_11.interrupted;

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

类Run.java代码

package test1_11.interrupted;

public class Run {
    public static void main(String[] args) throws InterruptedException {
        try {
            MyThread thread = new MyThread();
            thread.start();
            Thread.sleep(20);
            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!");
    }
}

程序运行结果

java线程超时后解除等待 java线程停止的几种方法_java线程超时后解除等待_02


Run.java 类虽然通过在 thread 对象上调用代码:


thread.interrupt();


来停止 thread对象所代表的线程,在后面又使用代码:


System.out.println("    是否停止 
   1 
   ? 
   ="+thread.interrupted()); 
   
System.out.println("    是否停止 
   2 
   ? 
   ="+thread.interrupted());


来判断thread对象所代表的线程是否停止,但从控 制台输出的结果来看,线程并未停止,这也证明了interrupted()方法的解释:测试当前线程是否已经中断。这个“当前线程”是main,从未中断过,所以输出的结果是2个false


注意


测试代码中使用 thread.interrupted()来判断 currentThread()是否被中断,也可以使用代码 Thread.interrupted() 判断,因为在 Thread.java类中调用静 态 static 方法时,大多数是针对 currentThread()线程进行 操作的。


如何使main线程有中断效果


创建Run2.java

package test1_11.interrupted;

public class Run2 {
    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!");
    }
}

运行结果

是否停止1?=true
是否停止2?=false
end!

java线程超时后解除等待 java线程停止的几种方法_java_03


从上述结果来看, interrupted()方法的确判断了当 前线程是否是停止状态,但为什么第二个布尔值是false 呢?查看一下 interrupted()方法在官方帮助文档中的解释:



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


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


isInterrupted()方法的声明如下

public boolean isInterrupted()

从声明中可以看出isInterrupted()方法不是static()方 法,作用于调用这个方法的对象

创建MyThread.java类

package test1_11.interrupted;

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

创建Run3.java类

package test1_11.isInterrupted;


import test1_11.interrupted.MyThread;

public class Run3 {
    public static void main(String[] args) {
        try {
            MyThread thread = new MyThread();
            thread.start();
            Thread.sleep(2);
            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!");
    }
}

运行结果

java线程超时后解除等待 java线程停止的几种方法_java代码_04


从结果中可以看到,isInterrupted()方法并未清除状 态标志,不具有此功能,所以输出两个 true 。


综上所述,这两个方法的区别如下

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

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


能停止的线程——异常法

根据前面所学知识,只需要通过线程的for语句来判断 一下线程是否处于停止状态即可判断后面的代码是否可运 行,如果线程处于停止状态,则后面的代码不再运行

类MyThread.java代码

package test1_11.test1;

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

类Run.java代码

package test1_11.test1;

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

运行结果

java线程超时后解除等待 java线程停止的几种方法_java_05

 

但如果for语句下面还有语句,那么程序还是会继续运行。

类MyThread.java代码

package test1_11.test2;

public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 1000; i++) {
            if (this.interrupted()) {
                System.out.println("已经是停止状态了!我要退出了!");
                break;
            }
            System.out.println("i=" + (i + 1));
        }
        System.out.println("我被输出,如果此代码是for又继续运行,线程并未停止!");
    }
}

文件Run.java代码

package test1_11.test2;

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

运行结果

java线程超时后解除等待 java线程停止的几种方法_java代码_06


如何解决语句继续运行的问题呢?



看一下更新后的代码

类MyThread.java代码

package test1_11.test3;

public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            for (int i = 0; i < 1000; 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();
        }
    }
}

类Run.java代码

package test1_11.test3;

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

运行结果

java线程超时后解除等待 java线程停止的几种方法_java线程超时后解除等待_07


由程序运行结果可以看出,线程终于被正确停止了。 这种方式就是前面 介绍的第三种停止线程的方法 ——使用 interrupt() 方法中断线程



在sleep状态下停止线程

类MyThread.java代码

package test1_11.test4;

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();
        }
    }
}

文件Run.java代码

package test1_11.test4;

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!");
    }
}

运行效果

java线程超时后解除等待 java线程停止的几种方法_java_08


从运行结果来看,如果线程在 sleep状态下停止,则该线程 会进入 catch 语句,并且清除停止状态值,变成 false。 标例是先调用 sleep() 方法,再调用interrupt()方法停止线 程,



先调用 interrupt()方法,再调用sleep()方法


还有一个反操作在学习线程时也要注意,即先调用 interrupt() 方法,再调用 sleep()方法,这种情况下也会出现异 常。



类MyThread.java代码

package test1_11.test5;

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();
        }
    }
}

类Run.java代码

package test1_11.test5;

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

运行结果

java线程超时后解除等待 java线程停止的几种方法_System_09


不管其调用的顺序,只要 interrupt() 和 sleep()方法碰到一起 就会出现异常:


1 )在 sleep 状态执行 interrupt() 方法会出现异常;

2 )调用 interrupt()方法给线程打了中断的标记,再执行 sleep() 方法也会出现异常。

用stop()方法暴力停止线程


使用 stop()方法可以强行停止线程,即暴力停 止线程。


文件 MyThread.java代码

package test1_11.test6;

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

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

文件Run.java代码

package test1_11.test6;

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

运行结果

java线程超时后解除等待 java线程停止的几种方法_java_10


由运行结果可以看出,线程被暴力停止了, 这种方式就是前面 介绍的第二种停止线程的方法


—— 使用stop()方法强行终止线程。


stop()方法呈删除线程状态,是不再被采用的 方法,原因是 stop() 方法容易造成业务处理的不确


定性;

例如, A 线程执行如下业务:

增加数据1

增加数据2

增加数据3

增加数据4


这时在任意时机对A线程调用stop()方法,A线程并不能确定在哪里被停止了,造成数据增加得


不完整。


stop()方法与java.lang.ThreadDeath 异常

调用 stop()方法时会抛出java.lang.ThreadDeath异常,但在通常情况下,此异常不需要显式地捕捉


文件MyThread.java代 码

package test1_11.test7;

public class MyThread extends Thread {
    @Override
    public void run() {
        try {
            this.stop();
        } catch (ThreadDeath e) {
            System.out.println("进入了catch()方法!");
            e.printStackTrace();
        }
    }
}

文件Run.java代码

package test1_11.test7;

public class Run {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
    }
}

运行结果

java线程超时后解除等待 java线程停止的几种方法_java代码_11

stop()方法已经是作废的方法,因为如果暴力 性地强制让线程停止,则一些清理性的工作可能 得不到完成,或者数据添加不完整。

使用stop()释放锁给数据造成不一致的结果

对锁定的对象进行 “ 解锁”,会导致数据得不到同步的处 理,进而出现数据不一致的问题。本节将会讲解使用stop()释放 锁给数据造成不一致性的结果,如果出现这样的情况,则程序 处理的数据完全有可能遭到破坏,最终导致程序执行的流程是 错误的,在此一定要注意。

文件MyService.java代码

package test1_11.test8;

public class MyService {
    private String username = "a";
    private String password = "aa";

    synchronized public String getUsername() {
        return username;
    }

    synchronized public String getPassword() {
        return password;
    }

    synchronized public void printString(String username, String password) {
        try {
            this.username = username;
            Thread.sleep(100000000);
            this.password = password;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

调用业务方法printString()的线程代码

package test1_11.test8;

public class MyThreadA extends Thread {
    private MyService object;

    public MyThreadA(MyService object) {
        super();
        this.object = object;
    }

    @Override
    public void run() {
        object.printString("b", "bb");
    }
}

输出username和password的线程代码

package test1_11.test8;

public class MyThreadB extends Thread {
    private MyService object;

    public MyThreadB(MyService object) {
        super();
        this.object = object;
    }

    @Override
    public void run() {
        System.out.println("username=" + object.getUsername());
        System.out.println("password=" + object.getPassword());
    }
}

文件Run.java代码

package test1_11.test8;

public class Run {
    public static void main(String[] args) {
        try {
            MyService object = new MyService();
            MyThreadA threadA = new MyThreadA(object);
            threadA.start();
            Thread.sleep(100);
            MyThreadB threadB = new MyThreadB(object);
            threadB.start();
            Thread.sleep(3000);
            threadA.stop();
            System.out.println("stop()执行后,在下方开始打印username和password。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果

java线程超时后解除等待 java线程停止的几种方法_开发语言_12

由于 stop() 方法已经在 JDK 中被标明是 “ 作废 / 过期 ”的方法, 显然它在功能上具有缺陷,所以不建议在程序中使用 stop()方法 停止线程。

 

使用“return;”语句停止线程的缺点与解决 方案


将 interrupt() 方法与 “return ; ”语句结合使用也能实现停 止线程的效果。


线程类 MyThread.java代码

package test1_11.test9;

public class MyThread extends Thread {
    @Override
    public void run() {
        int i=0;
        while (true) {
            if (this.isInterrupted()) {
                System.out.println("停止了!");
                return;
            }
            System.out.println("i=" + i++);
        }
    }
}

运行类Run.java代码

package test1_11.test9;

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

运行结果

java线程超时后解除等待 java线程停止的几种方法_java_13

虽然使用 “return ; ” 较 “ 抛异常 ”法在代码结构上可以更 加方便地实现线程的停止,不过还是建议使用 “抛异常”法, 因为在catch块中可以对异常的信息进行统一的处理,

例 如,使用“return;”来设计代码:

package test1_11.test10;

public class MyThread extends Thread {
    @Override
    public void run() {
        // insert操作
        if (this.interrupted()) {
            System.out.println("写入log info");
            return;
        }
        // update操作
        if (this.interrupted()) {
            System.out.println("写入log info");
            return;
        }
        // delete操作
        if (this.interrupted()) {
            System.out.println("写入log info");
            return;
        }
        // select操作
        if (this.interrupted()) {
            System.out.println("写入log info");
            return;
        }
        System.out.println("for for for for for");
    }
}

在每个 “return ;”代码前都要搭配一个写入日志的代 码,这样会使代码出现冗余,不利于代码的阅读与扩展, 这时可以使用 “抛异常”法来简化这段代码:


 

package test1_11.test10;

public class MyThread2 extends Thread {
    @Override
    public void run() {
        try {
            // insert操作
            if (this.interrupted()) {
                throw new InterruptedException();
            }
            // update操作
            if (this.interrupted()) {
                throw new InterruptedException();
            }
            // delete操作
            if (this.interrupted()) {
                throw new InterruptedException();
            }
            // select操作
            if (this.interrupted()) {
                throw new InterruptedException();
            }
            System.out.println("for for for for for");
        } catch (InterruptedException e) {
            System.out.println("写入log info");
            e.printStackTrace();
        }
    }
}


写入日志的功能在 catch块中被统一处理了,代码风格 更加标准。