java程序中,如何安全的结束一个正在运行的线程?

转载:http://blog.163.com/xh_ding/blog/static/193903289201341685931689

在Java的多线程编程中,java.lang.Thread 类型包含了一些列的方法start(), stop(), stop(Throwable) and suspend(), destroy() and resume()。通过这些方法,我们可以对线程进行方便的操作,但是这些方法中,只有start()方法得到了保留。

那么,我们究竟应该如何停止线程呢?这里我们介绍两种方法:

1、使用共享变量的方式

在这种方式中,之所以引入共享变量,是因为该变量可以被多个执行相同任务的线程用来作为是否中断的信号,通知中断线程的执行。

public class ThreadFlag extends Thread { 
        
        public volatile boolean exit = false; //共享变量

        public void run() { 
            while (!exit); 
        } 
        
        
        public static void main(String[] args) throws Exception { 
            
            ThreadFlag thread1 = new ThreadFlag(); 
            thread1.start(); 
            
            sleep(3000);            // 主线程延迟3秒 
            thread1.exit = true;    // 由主线程改变共享变量的值,终止线程thread1 
            thread1.join();         // 主线程等待thread1结束
            System.out.println("thread1线程退出了!"); 
        } 
    }

在上面代码中定义了一个退出标志exit,作为共享变量,当exit为true时,while循环退出,exit的默认值为false。在定义exit时,使用了一个Java关键字volatile,这个关键字的目的是使exit同步,也就是说在同一时刻只能由一个线程来修改exit的值。

2、使用interrupt方法终止线程

如果一个线程由于等待某些事件的发生而被阻塞,又该怎样停止该线程呢?

这种情况经常会发生,比如当一个线程由于需要等候键盘输入而被阻塞,或者调用Thread.join()方法,或者Thread.sleep()方法,在网络中调用ServerSocket.accept()方法,或者调用了DatagramSocket.receive()方法时,都有可能导致线程阻塞,使线程处于处于不可运行状态时。

即使主程序中将该线程的共享变量设置为true,但该线程此时根本无法检查循环标志,当然也就无法立即中断。

这里我们给出的建议是,不要使用stop()方法,而是使用Thread提供的interrupt()方法,因为该方法虽然不会中断一个正在运行的线程,但是它可以使一个被阻塞的线程抛出一个中断异常,从而使线程提前结束阻塞状态,退出堵塞代码。

public class InterruptThread {
    
    public static void main(String[] args) throws InterruptedException {
        
        MyThread myThread1 = new MyThread();
        System.out.println("启动线程.");
        myThread1.start();
        Thread.sleep(3000);
        System.out.println("中断线程: " + myThread1.getName());
        myThread1.stop = true;  // 设置共享变量为true
        myThread1.interrupt();  // 阻塞时退出阻塞状态
        Thread.sleep(3000);     // 主线程休眠3秒以便观察线程m1的中断情况
        System.out.println("结束.");
    }
}


class MyThread extends Thread {
    
    public volatile boolean stop = false;   //共享变量

    public void run() {
        while (!stop) {
            System.out.println(getName() + " 正在运行...");
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("抛出异常, 从阻塞中被唤醒.");
                stop = true; // 在异常处理代码中修改共享变量的状态
            }
        }
        System.out.println(getName() + " 线程退出.");
    }
}

interrupt()方法,将会设置该线程的中断状态位,即设置为true。注意,线程中断仅仅是设置线程的中断状态位,不会停止线程。需要用户自己去监视线程的状态位并做出处理。

注意
在Thread类中有两个方法可以判断线程是否通过interrupt方法被终止。

一个是静态的方法interrupted(),一个是非静态的方法isInterrupted()。

这两个方法的区别
interrupted()用来判断当前线是否被中断,而isInterrupted()可以用来判断其他线程是否被中断。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 一、进程和线程 进程 进程就是一个执行中的程序实例,每个进程都有自己独立的一块内存空间,一个进程中可以有多个线程。...
    阿敏其人阅读 7,432评论 0 13
  • 一、线程的生命周期 线程状态转换图: 1、新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线...
    我是嘻哈大哥阅读 4,492评论 0 8
  • 文章转自 线程对象属于一次性消耗品,一般线程执行完run方法之后,线程就正常结束了,线程结束之后就报废了,不能再次...
    隔壁老C阅读 4,831评论 0 0
  • 一、认识多任务、多进程、单线程、多线程 要认识多线程就要从操作系统的原理说起。 以前古老的DOS操作系统(V 6....
    GT921阅读 4,629评论 0 3
  • 这次带妈妈出游,到处冒傻气,为此花了不少冤枉钱,或者是学费吧。 许多时候是打着省钱的名义。到了海口的美兰机场,本能...
    曼谷123阅读 1,616评论 0 0

友情链接更多精彩内容