Java多线程编程——线程终止

在Java中有以下三种方法可以终止正在运行的线程:

1. 通过设置退出标志位,使线程正常退出。

2. 调用Thread类中的stop()方法强行终止线程。但是不推荐使用这个方法,该方法已被弃用。

3. 使用Thread类中的interrupt()方法中断线程。

一、使用标志位终止线程

在线程类中,我们会定义一个标志位表示是否需要终止线程,并提供一个公共方法供外部设置标志位,在run()方法中通过标志位的取值判断是否需要终止。

例如,我们模拟了一个服务器不断接收客户端请求的过程。当主线程中将“running”这一标志位设为false后,while死循环就会结束,线程体执行结束,整个线程也就执行完毕了。

public class Main {
    public static void main(String[] args) throws InterruptedException {
        // start a thread (simulated server)
        Server server = new Server();
        new Thread(server).start();

        // run the thread for about 10 seconds
        Thread.sleep(10000);

        // time to stop the thread
        server.setRunning(false);
    }
}

class Server implements Runnable {
    // whether the server should be running or not
    private volatile boolean running = true;

    // setter method for user
    public void setRunning(boolean running) { this.running = running; }

    @Override
    public void run() {
        // run until the flag is set to be false
        while (running) {
            // simulate the process of server to handle the request
            System.out.println("Server is processing the request...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // finish the process and stop the thread
        System.out.println("Server is closing...");
    }
}

二、调用stop()方法终止线程

通过调用Thread类中的stop()方法可以终止一个线程的运行,但是该方法已经在JDK中被声明为已过时(deprecated),不再推荐使用,因为该方法被认为是不安全的。具体的原因有:

1. 调用stop()方法会立刻停止run()方法中剩余的全部工作,包括在catch或finally语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。

2. 调用stop()方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。

例如,存在一个对象user持有ID和NAME两个字段,假如写入线程在写对象的过程中,只完成了对ID的赋值,但没来得及为NAME赋值,就被stop()导致锁被释放,那么当读取线程得到锁之后再去读取对象user的ID和Name时,就会出现数据不一致的问题。

三、调用interrupt()方法终止线程

通过调用Thread类中的interrupt()方法也可以终止线程,但是它和stop()还是有着明显的区别。事实上,interrupt()方法并不会立即执行中断操作,而只是给线程设置一个为true的中断标志,所以它并不是真正的终止线程(否则那和stop()方法有什么区别了呢)。

来看下面一个例子:

public class Main {
    public static void main(String[] args) throws InterruptedException {
        // start a thread
        Task task = new Task();
        Thread thread = new Thread(task);
        thread.start();

        // wait for 5ms
        Thread.sleep(5);

        // now we interrupt the thread
        thread.interrupt();
    }
}

class Task implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            System.out.println("In Thread: " + i);
        }
    }
}

上述程序的输出结果如下:

In Thread: 0
In Thread: 1
In Thread: 2
In Thread: 3
In Thread: 4
In Thread: 5
............
In Thread: 9995
In Thread: 9996
In Thread: 9997
In Thread: 9998
In Thread: 9999

我们惊讶的发现,线程体居然顺利的全部执行完了,设置的中断完全没有起到作用。为了让线程能够中断,我们需要在run()方法中使用isInterrupted()方法进行判断:如果希望线程在中断后停止,就必须先判断是否被中断,并为它增加相应的中断处理代码。

public class Main {
    public static void main(String[] args) throws InterruptedException {
        // start a thread
        Task task = new Task();
        Thread thread = new Thread(task);
        thread.start();

        // wait for 5ms
        Thread.sleep(5);

        // now we interrupt the thread
        thread.interrupt();
    }
}

class Task implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            // check whether the thread is interrupted
            if (Thread.currentThread().isInterrupted())
                // if true, break the loop
                break;
            System.out.println("In Thread: " + i);
        }
    }
}

修改后程序的运行结果如下:

In Thread: 0
In Thread: 1
In Thread: 2
In Thread: 3
.............
In Thread: 207
In Thread: 208
In Thread: 209
In Thread: 210
In Thread: 211
In Thread: 212

显然,线程体远未执行完毕就被中断提前结束了。

需要注意的是,

1. 如果,线程的当前状态处于非阻塞状态,那么仅仅是线程的中断标志被修改为true而已;

2. 如果线程的当前状态处于阻塞状态,那么在将中断标志设置为true后,如果是wait、sleep以及join三个方法引起的阻塞,那么会将线程的中断标志重新设置为false,并抛出一个InterruptedException,这样受阻线程就得以退出阻塞的状态。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值