多线程基础四(二)、能停止的线程(异常法、sleep、return、interrupt、stop)

我们先来看一个例子,在 for 循环中判断线程是否中断,如果中断则后面代码不再运行:
public class MyThread extends Thread {
    @Override
    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("我被输出,如果此代码是 for 又继续运行,线程并未停止!");
    }
}
public class Test {
    public static void main(String[] args) {
        try {
            MyThread thread = new MyThread();
            thread.start();
            Thread.sleep(1000);
            thread.interrupt();
        } catch (InterruptedException e) {
            System.out.println("main catch");
            e.printStackTrace();
        }
        System.out.println("end!");
    }
    /*
    运行结果:
    ...
    i = 287846
    i = 287847
    已经是停止状态了!我要退出了!
    我被输出,如果此代码是 for 又继续运行,线程并未停止!
    end!
     */
}

从结果上看,for 循环中的 break 只是结束了循环。如果 for 下面还有语句,依然会继续执行。那么如何解决语句继续执行的问题?

1. 抛出异常

public class MyThread2 extends Thread {
    @Override
    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("我在 for 下面");
        } catch (InterruptedException e) {
            System.out.println("进 MyThread.java 类 run 方法中的 catch 了!");
            e.printStackTrace();
        }
    }
}
public class Test2 {
    public static void main(String[] args) {
        try {
            MyThread2 thread = new MyThread2();
            thread.start();
            Thread.sleep(1000);
            thread.interrupt();
        } catch (InterruptedException e) {
            System.out.println("main catch");
            e.printStackTrace();
        }
        System.out.println("end!");
    }
    /*
    运行结果:
    ...
    i = 304678
    i = 304679
    end!
    已经是停止状态了!我要退出了!
    进 MyThread.java 类 run 方法中的 catch 了!
    java.lang.InterruptedException
        at com.leo.JavaImprove.chapter1.exceptionStopThread.MyThread2.run(MyThread2.java:15)
     */
}
从结果中可以看出,使用 抛出异常的方法之后,for 循环后面的语句并没有被继续执行了。

2. 在沉睡中停止
public class MyThread3 extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            System.out.println("run begin");
            Thread.sleep(20000);
            System.out.println("run end");
        } catch (InterruptedException e) {
            System.out.println("在沉睡中被停止!进入 catch!" + this.isInterrupted());
            e.printStackTrace();
        }
    }
}
public class Test3 {
    public static void main(String[] args) {
        try {
            MyThread3 thread = new MyThread3();
            thread.start();
            Thread.sleep(200);
            thread.interrupt();
        } catch (InterruptedException e) {
            System.out.println("main catch");
            e.printStackTrace();
        }
        System.out.println("end!");
    }
    /*
    运行结果:
    run begin
    java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at com.leo.JavaImprove.chapter1.exceptionStopThread.MyThread3.run(MyThread3.java:13)
    end!
    在沉睡中被停止!进入 catch!false
     */
}
如果在 sleep 状态下停止线程,会进入 catch 语句(相当于前面的 throw new InterruptedException),并且清楚停止状态值,使 isInterrupted = false。
上面这个例子是先开始了线程中的sleep,然后再用 interrupt() 停止。下面我们反过来,再看看:
public class MyThread4 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!" + this.isInterrupted());
            e.printStackTrace();
        }
    }
}
public class Test4 {
    public static void main(String[] args) {
        MyThread4 thread = new MyThread4();
        thread.start();
        thread.interrupt();
        System.out.println("end!");
    }
    /*
    运行结果:
    end!
    i = 1
    i = 2
    ...
    i = 99999
    i = 100000
    run begin
    先停止,再遇到了sleep!进入 catch!false
    java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
     */
}

所以,线程在运行后,先用 interrupt() 停止后执行到 sleep() 也会抛出异常,停止线程。

3. 暴力停止 stop()

public class MyThread extends Thread {
    private int i = 0;
    @Override
    public void run() {
        try {
            while (true) {
                i++;
                System.out.println("i = " + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        try {
            MyThread thread = new MyThread();
            thread.start();
            Thread.sleep(8000);
            thread.stop();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /*
    i = 1
    i = 2
    i = 3
    i = 4
    i = 5
    i = 6
    i = 7
    i = 8
    i = 9
     */
}
可见 stop() 方法会立刻停止线程,同时会释放锁,可能会使数据不一致。调用 stop() 方法时会抛出 java.lang.ThreadDeath 异常,通常情况下,此异常不需要显示地捕捉。stop() 方法已经被作废,不建议使用。
public class MyThread2 extends Thread {
    @Override
    public void run() {
        try {
            stop();
        } catch (ThreadDeath e) {
            System.out.println("进入了 catch 方法!");
            e.printStackTrace();
        }
    }
}
public class Test2 {
    public static void main(String[] args) {
        MyThread2 thread = new MyThread2();
        thread.start();
    }
    /*
    进入了 catch 方法!
    java.lang.ThreadDeath
        at java.lang.Thread.stop(Thread.java:836)
     */
}
下面我们看一个 stop() 释放锁的例子:
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;
    }

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

    private SynchronizedObject object;

    public MyThread3(SynchronizedObject object) {
        super();
        this.object = object;
    }

    @Override
    public void run() {
        object.printString("b", "bb");
    }
}
public class Test3 {
    public static void main(String[] args) {
        try {
            SynchronizedObject object = new SynchronizedObject(); //实例化 object,此时 username=a, password=aa
            MyThread3 thread = new MyThread3(object);
            thread.start(); //开始线程,执行 printString 方法
            Thread.sleep(500); //挂起 main 线程,留时间给 thread.printString("b", "bb")执行,此时 this.username = "b"
            thread.stop(); //停止线程 thread, 同时也释放了 线程中 printString()的方法锁。这个时候object.username的值已经变成 b了,而password还没有改变
            System.out.println(object.getUsername() + " -- " + object.getPassword());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /*
    运行结果:
    b -- aa
     */
}
4. 使用 return 停止线程,将 interrupt() 与 return 结合使用也能实现停止线程的效果
public class MyThread extends Thread {
    @Override
    public void run() {
        while (true) {
            if (this.isInterrupted()) {
                System.out.println("线程停止了!");
                return;
            }
            System.out.println("timer = " + System.currentTimeMillis());
        }
    }
}
public class Test {
    public static void main(String[] args) {
        try {
            MyThread thread = new MyThread();
            thread.start();
            Thread.sleep(2000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /*
    运行结果:
    timer = 1503565757740
    timer = 1503565757740
    timer = 1503565757740
    timer = 1503565757740
    timer = 1503565757740
    timer = 1503565757740
    timer = 1503565757740
    线程停止了!
     */
}
虽然return 也可以停止线程,但还是 建议使用“抛异常”法来实现线程的停止,因为在 catch 块中可以对异常的信息进行相关的处理,而且使用异常流能更好、更方便地控制程序的运行流程,不至于代码中出现很多个 return;造成污染。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值