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()可以用来判断其他线程是否被中断。

你可能感兴趣的:(java程序中,如何安全的结束一个正在运行的线程?)