多线程并发篇——如何中止线程

  笔者是广州的java程序员,刚毕业半年,工做之余写博客,若是以为个人文章写得不错,能够关注个人微信公众号(J2彬彬),里面会有更多精彩内容。从2018年8月份开始写博客,但愿往后写出更多通俗易懂的技术文章与你们一同分享。java

前言

  你有没有想过,如何中止一个线程?不少人首先会想到Thread.stop()方法,可是这个方法已通过时,不推荐使用,由于这个方法会带来安全问题,什么安全问题呢?后面会有详细说明。咱们先讲讲目前JDK API推荐使用中止线程的方法Thread.interrupt()方法。程序员

Thread.interrupt()

  既然不能直接stop线程,那么只有一种方法可让线程结束,那就是让run方法运结束。   Thread.interrupt()表明的意思是“中止,停止”。可是这个方法须要加入一个判断才能够完成线程的中止。一旦检测到线程处于中断状态,那么就有机会结束run方法。   下面以一个代码示例看看它是如何中止线程的?安全

1、interrupt()中止线程
package com.bingo.thread.stopThread;

/** * Created with IntelliJ IDEA. * Description: 中止线程不推荐使用stop方法,此方法不安全,咱们可使用Thread.interrupt() * User: bingo */
public class Run {

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myThread.interrupt();
        System.out.println("end...");
    }
}


class MyThread extends Thread{

    @Override
    public void run() {
        super.run();

        for (int i = 0; i < 10000 ; i++) {

            if(this.isInterrupted()){
                System.out.println("已是中止状态了,我要退出了");
                break;
            }
            System.out.println("i="+(i+1));
        }
    }
}
复制代码

运行结果:微信

i=1
......
i=3102
i=3103
i=3104
i=3105
i=3106
i=3107
i=3108
end...
已是中止状态了,我要退出了
复制代码

  运行结果咱们能够看到,当myThread线程的循环运行到i=3108的时候,因为线程被中断,而跳出循环,这个例子很好诠释了interrupt方法的做用。多线程

2、interrupt能够清除线程的冻结状态,让线程恢复到可运行的状态上来
package com.bingo.thread.stopThread;

/** * Created with IntelliJ IDEA. * Description: interrupt能够清除线程的冻结状态,让线程恢复到可运行的状态上来。 * User: bingo */
public class Run2 {

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

class MyThread2 extends Thread{

    @Override
    public void run() {
        System.out.println("run begin...");
        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            System.out.println("run 在沉睡中被停止,进入catch");
            e.printStackTrace();
        }
        System.out.println("run end...");
    }
}
复制代码

运行结果:ide

main end...
run begin...
run 在沉睡中被停止,进入catch
run end...
java.lang.InterruptedException: sleep interrupted
 at java.lang.Thread.sleep(Native Method)
 at com.bingo.thread.stopThread.MyThread2.run(Run2.java:26)
复制代码

  从运行结果咱们能够看到,原本run方法睡眠时间为1000秒,可是打印结果倒是瞬间的,其实sleep已经被interrupt方法给打断,此时线程冻结状态被清除,并抛出异常,被catch捕获,打印异常信息。学习

暴力中止——Stop

  下图是JDK API对stop方法的描述,能够看到已过期,不推荐使用,并告诉咱们此方法为什么不安全? this

  若是某个线程加锁,stop方法中止该线程时会把锁释放掉,可能形成数据不一致的状况。下面代码能够说明此问题。

package com.bingo.thread.stopThread;

/** * Created with IntelliJ IDEA. * Description: stop()方法为什么不安全?下面例子可解答 * User: bingo */
public class StopTest {

    public static void main(String[] args) {

        try {

            SynchrionzedObject object = new SynchrionzedObject();
            MyThread3 t = new MyThread3(object);
            t.start();

            Thread.sleep(500);

            t.stop();

            System.out.println(object.getUsername()+" "+object.getPassword());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

class SynchrionzedObject{

    private String username = "a";

    private String password = "aa";

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public synchronized void printString(String username,String password){
        try {

            this.username = username;
            Thread.sleep(10000);
            this.password = password;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

class MyThread3 extends Thread{

    private SynchrionzedObject object;

    public MyThread3(SynchrionzedObject object){
        this.object = object;
    }

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

复制代码

运行结果:spa

b aa
复制代码

  从上面例子咱们能够看到虽然printString方法加了锁,可是run方法运行过程当中忽然被stop了,锁被释放,MyThread线程只对username进行了赋值,而password赋值动做未执行,此时形成数据不一致。线程

最后

  其实java多线程不少方法内部都是native方法,也就是基于JVM内部实现的,因此咱们有必要结合JVM一块儿学习这部分的内容。技术的进步须要每一个小小的积累,才能走得更远,更长久。

相关文章
相关标签/搜索