Java多线程学习笔记 - 如何完美的中断线程

一、中断线程

        当 run() 方法完成时,线程会自动销毁。但是可能需要在线程完成其生命周期之前杀死/停止线程。以前,方法suspend()resume()stop()用于管理线程的执行。但是这些方法在Java中被弃用了,因为它们可能导致系统崩溃。

        挂起/停止线程的方法是使用布尔标志和Thread.interrupt()方法。

1、使用布尔标志

        创建一个实现Runnable接口的类,其中类内有Boolean的标志,以及stop方法。

class MyThread implements Runnable {
 
    // to stop the thread
    private boolean exit;
 
    private String name;
    Thread t;
 
    MyThread(String threadname)
    {
        name = threadname;
        t = new Thread(this, name);
        System.out.println("New thread: " + t);
        exit = false;
        t.start(); // Starting the thread
    }
 
    // execution of thread starts from run() method
    public void run()
    {
        int i = 0;
        while (!exit) {
            System.out.println(name + ": " + i);
            i++;
            try {
                Thread.sleep(100);
            }
            catch (InterruptedException e) {
                System.out.println("Caught:" + e);
            }
        }
        System.out.println(name + " Stopped.");
    }
 
    // for stopping the thread
    public void stop()
    {
        exit = true;
    }
}
 
// Main class
public class Main {
    public static void main(String args[])
    {
        // creating two objects t1 & t2 of MyThread
        MyThread t1 = new MyThread("First  thread");
        MyThread t2 = new MyThread("Second thread");
        try {
            Thread.sleep(500);
            t1.stop(); // stopping thread t1
            t2.stop(); // stopping thread t2
            Thread.sleep(500);
        }
        catch (InterruptedException e) {
            System.out.println("Caught:" + e);
        }
        System.out.println("Exiting the main Thread");
    }
}

2、使用原子布尔标志

        创建一个实现Runnable接口的类,其中类内有AtomicBoolean的标志,以及stop方法。

package com.algorithm.demo.thread;

import java.util.concurrent.atomic.AtomicBoolean;

public class MyThreadDemo implements Runnable
{
    // to stop the thread
    private final AtomicBoolean running = new AtomicBoolean(false);

    private String name;
    Thread t;

    public MyThreadDemo(String threadname)
    {
        name = threadname;
        t = new Thread(this, name);
        System.out.println("New thread: " + t);
        t.start(); // Starting the thread
    }

    // execution of thread starts from run() method
    public void run()
    {
        running.set(true);
        int i = 0;
        while (!running.get()) {
            System.out.println(name + ": " + i);
            i++;
            try {
                Thread.sleep(100);
            }
            catch (InterruptedException e) {
                System.out.println("Caught:" + e);
            }
        }
        System.out.println(name + " Stopped.");
    }

    public void stop() {
        running.set(false);
    }
}

        调用并创建线程,并调用stop改变AtomicBoolean的值。 

@Test
void thread_stop_with_bool()
{
    // creating two objects t1 & t2 of MyThread
	MyThreadDemo t1 = new MyThreadDemo("First  thread");
	MyThreadDemo t2 = new MyThreadDemo("Second thread");
	try {
		Thread.sleep(500);
		t1.stop(); // stopping thread t1
		t2.stop(); // stopping thread t2
		Thread.sleep(500);
	}
	catch (InterruptedException e) {
		System.out.println("Caught:" + e);
	}
	System.out.println("Exiting the main Thread");
}

2、使用 Thread.interrupt() 方法

        当对一个线程,调用其interrupt()方法时。

        1、 如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。
        2、如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true。被设置中断标志的线程将继续正常运行,不受影响。

        在调用阻塞方法时正确处理InterruptedException异常,catch后就会结束线程。

package com.algorithm.demo.thread;

import java.util.concurrent.atomic.AtomicBoolean;

public class ControlSubThread implements Runnable {

    private Thread worker;
    private AtomicBoolean running = new AtomicBoolean(false);
    private AtomicBoolean stopped = new AtomicBoolean(false);
    private int interval = 50000;

    // ...

    public void interrupt() {
        running.set(false);
        worker.interrupt();
    }

    public void start() {
        worker = new Thread(this);
        worker.start();
    }

    boolean isRunning() {
        return running.get();
    }

    boolean isStopped() {
        return stopped.get();
    }

    public void run() {
        running.set(true);
        stopped.set(false);
        while (running.get()) {
            try {
                Thread.sleep(interval);
            } catch (InterruptedException e){
                Thread.currentThread().interrupt();
                System.out.println(
                        "Thread was interrupted, Failed to complete operation");
            }
            // do something
        }
        stopped.set(true);
    }
}

3、总结

        如果想要中断一个线程。

        1、如果中断标志位不会被多个线程使用,则可以使用boolean标志位,否则使用AtomicBoolean标志位(根据情况考虑是否使用静态)。

        2、在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程。

        3、在调用阻塞方法时正确处理InterruptedException异常。(catch异常后就结束线程。)

猜你喜欢

转载自blog.csdn.net/bashendixie5/article/details/123507783