线程中断的方式 interrupt与volatile

Thread.stop()方法

  • 此方法虽然可以立即停止线程,但是是不安全的方法。已被废弃。
  • 如果强制使用此方法停止线程,可能会使一些清理工作得不到完成。另外一个情况就是对锁的对象进行了解锁,导致数据得不到同步的问题。

interrupt()方法

  • 调用此方法会在当前线程中打一个停止的标记,并不会真正的停止线程。
  • 要想真正的停止线程,还需要结合interrupted()isInterrupted()

interrupted | interrupted

  • interrupted: 测试当前线程是否处已经中断
  • isInterrupted: 测试线程是否处已经中断

interrupted的方法声明

publc static boolean interrupted();

isInterrupted的方法声明

publc boolean isInterrupted();

两者的区别

  1. interrupted:判断的是当前线程 this.interrupted()
  2. isInterrupted: 判断的是调用此方法的线程
  3. interrupt() 方法执行后,调用interrupted() | isInterrupted() ,会打印为true(默认为false)。
    false代表线程未中断,true为线程中断。而interrupted()方法具有清除状态的功能,所以如果第二次调用 interrupted() 方法会返回false;

异常法终止线程

即使用interruptedisInterrupted进行判断,满足条件就抛出异常

class MyThread implements Runnable {

    @Override
    public void run() {
        try {
            for (int i=0;i<100;i++){
                if (Thread.currentThread().interrupted()){
                    System.out.println("线程要被终止");
                    throw new InterruptedException();
                }
                System.out.println(i);
            }
            System.out.println("-----"+ "线程终止后我将不再执行");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println("线程终止了");
        }
    }
}

在睡眠中终止线程

如下代码

class Interrupt implements Runnable {
    @Override
    public void run() {
        int sun = 0;
        try {
            while (!Thread.currentThread().isInterrupted() && sun < 10000) {
                if (sun % 100 == 0) {
                    System.out.println(sun);
                }
                sun++;

                Thread.sleep(500);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println("------------+++++");
        }
 @Test
   public void demo01() throws InterruptedException {
        Runnable runnable = new Interrupt();
        Thread thread = new Thread(runnable);
        thread.start();
        thread.sleep(1000);
        thread.interrupt();
    }

在sleep状态下停止线程,会直接进入clatch语句,并且清除中断状态值,使之变成false
当线程处于wait()时,执行 interrupt() 也会抛出InterruptedException异常。此时无需判断Thread.currentThread().isInterrupted()

return方法终止线程

class s implements Runnable{
    @Override
    public void run() {
        while (Thread.currentThread().isInterrupted()){
            System.out.println("-----"+ "线程终止后我将不再执行");
            return;
        }
    }
}

此方法不推荐使用,建议还是使用异常法,可以在catch块中进行相关的处理

私有堆栈与公有堆栈

线程的私有堆栈与公有堆栈,私有堆栈与公有堆栈中的数值是不同步的
如下代码

class PrintString implements  Runnable{
    private boolean iscont = true;

    public boolean isIscont() {
        return iscont;
    }

    public void setIscont(boolean iscont) {
        this.iscont = iscont;
    }

    @Override
    public void run() {
        System.out.println("进入到了run ···");
        while (iscont){
            System.out.println("---");
        }
        System.out.println("线程被终止了");
    }
    
}

class Run{
    public static void main(String[] args) {
        try {
            PrintString printString = new PrintString();
            Thread thread = new Thread(printString);

            thread.start();
            thread.sleep(1000); 
            
            printString.setIscont(false);
            System.out.println("已经赋值为false");
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

在JVM配置成Server的环境下执行此代码线程并不能停止,原因便是 私有堆栈与公有堆栈中的数值是不同步的。线程一直在私有堆栈中提取 boolean iscont = true; 而 printString.setIscont(false);更新的使公有堆中的数据。所以线程还是会处于死循环中。

volatile

volatile : 关键字的主要作用是使变量在多个线程间可见
使用此特性便可以进行线程的中断

中断线程

class PrintString implements  Runnable{
//此变量的类型
    private volatile boolean iscont = true;
    public boolean isIscont() {
        return iscont;
    }
    public void setIscont(boolean iscont) {
        this.iscont = iscont;
    }
    @Override
    public void run() {
        System.out.println("进入到了run ···");
        while (iscont){
            System.out.println("---");
        }
        System.out.println("线程被终止了");
    }
}

使用此关键字,便可强制线程从公有堆中获取数据

弊端

在线程处于阻塞状态时,此方法便不能够中断线程。
如下代码,生产者进行生产,消费者消费,生产的速度大于消费的速度。若满足生产的数量,则进入阻塞。

class VolatileProducers implements Runnable{

    //BlockingQueue 即阻塞队列
    BlockingQueue  blockingQueue ;
    public static volatile boolean cancel = false;

    Volatileroduction volatileroduction = new Volatileroduction();

    /**  构造方法*/
    public VolatileProducers(BlockingQueue blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        try {
            /** 调用过程未出现阻塞状态的方法 可以正常进行中断操作*/
            //volatileroduction.VolatileProducers1(cancel);

            /** 会产生处于阻塞状态*/
            volatileroduction.VolatileProducers2(cancel,blockingQueue);

            /** 使用interputed中断线程*/
            //volatileroduction.VolatileProducers3(cancel,blockingQueue);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println("--"+cancel);
            System.out.println("--"+Thread.interrupted());
        }
    }
}


/**
 * 生产者
 */
class Volatileroduction{

/** 不会产生阻塞的方法*/
    public void VolatileProducers1(boolean cancel) throws InterruptedException {
        int sum=0;
        while (sum < 10000 && !cancel){
            if (sum %100 ==0){
                System.out.println(sum);
            }
            sum++;
            Thread.sleep(10);
        }
    }

    //此方法在线程处于阻塞状态时,使用volatile并不会是线程中断
    public void VolatileProducers2(boolean cancel,BlockingQueue queue) throws InterruptedException {

        int sum=0;
        while (sum < 10000 && !cancel){
            if (sum %100 ==0){
                System.out.println("生产者生产了"+sum);
                //当阻塞队列满的时候,会处于阻塞状态,代码无法往下执行,自然无法进行while判段,也就无法中断线程
                queue.put(sum);
            }
            sum++;
        }
    }

	/**  interrupt() 方法*/
    public void VolatileProducers3(boolean cancel,BlockingQueue queue) throws InterruptedException {

        int sum=0;
        while (sum < 10000 && !Thread.currentThread().isInterrupted()){
            if (sum %100 ==0){
                System.out.println("生产者生产了"+sum);
                queue.put(sum);
            }
            sum++;
        }
    }
}


//消费者
class Consumers{

    BlockingQueue queue;

    public Consumers(BlockingQueue queue) {
        this.queue = queue;
    }

    public boolean needMoreNum(){
        if (Math.random() > 0.95){
            return false;
        }
        return true;
    }

}
//main方法调用
public static void main(String[] args) throws InterruptedException {

        ArrayBlockingQueue queue = new ArrayBlockingQueue(10);
        /** 生产者生产*/
        VolatileProducers producers = new VolatileProducers(queue);
        Thread producersthread = new Thread(producers);
        producersthread.start();
        producersthread.sleep(1000);

        /** 消费者*/
        Consumers consumers = new Consumers(queue);
        while (consumers.needMoreNum()){
            System.out.println(consumers.queue.take()+"被消费了");
            Thread.sleep(100);
        }
        System.out.println("无需消费");

        //将生产者停止生产
        producers.cancel = true;

		/** 中断线程*/
        //producersthread.interrupt();
    }

由以上代码可以看出,中断线程最好还是使用 interrupt()方法

volatile与synchronized 比较

  1. 性能上,前者要比后者好
  2. 范围上,volatile只能修饰变量,synchronized可以方法,代码快登
  3. synchronized会发生阻塞,volatile不会
  4. volatile 可以保证数据可见性,不能保证原子性。synchronized可以保证原子性,也可以间接保证可见性。
  5. 线程安全包含原子性和可见性两个方面。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 线程中写死循环会导致线程一直占用 CPU 资源,影响系统的性能和稳定性。如果需要中断线程,可以使用线程中断机制。 在 Java 中,线程中断机制通过调用线程interrupt() 方法实现。该方法会设置线程中断标志位,线程在执行过程中可以检查该标志位,如果标志位被设置,线程可以选择退出执行。 下面是一个示例代码: ```java public class MyThread extends Thread { @Override public void run() { while (!Thread.interrupted()) { // 线程执行的代码 } } } public class Main { public static void main(String[] args) throws InterruptedException { MyThread thread = new MyThread(); thread.start(); // 在主线程中等待一段时间后中断线程 Thread.sleep(1000); thread.interrupt(); } } ``` 在上面的代码中,MyThread 类继承自 Thread,重写了 run() 方法,在 run() 方法中使用 while 循环进行线程执行的代码。在 while 循环中使用 Thread.interrupted() 方法检查线程中断标志位,如果标志位被设置,while 循环会退出,线程也会结束执行。 在 Main 类中,创建了 MyThread 对象并启动线程。在主线程中等待一段时间后,调用 thread.interrupt() 方法中断线程的执行。 ### 回答2: 在线程使用死循环可能会导致线程无法正常退出,因为线程会一直停留在循环中,无法执行循环外的其他代码。但我们可以通过中断线程方式来解决这个问题。 要中断一个线程,我们可以使用Thread类提供的interrupt()方法。首先,在循环内部通过检查Thread类的interrupted()方法来确定是否发生了中断请求。如果发生了中断请求,我们可以使用break语句来跳出循环。接下来,我们可以使用return语句或者在循环外部进行清理操作,从而使线程正常退出。 以下是一个简单的示例代码: ```java public class MyThread extends Thread { @Override public void run() { while (!Thread.interrupted()) { // 循环体代码 // 检查是否发生中断 if (Thread.interrupted()) { break; } } // 清理操作 } } public class Main { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); // 等待一段时间后中断线程 try { Thread.sleep(1000); thread.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } } ``` 在这个示例中,我们创建了一个继承自Thread类的自定义线程类MyThread,并在run()方法中进行了死循环。在循环中,我们通过调用Thread.interrupted()方法来检查是否发生了中断请求。如果中断请求发生,我们使用break语句来跳出循环。在main方法中,我们创建了一个MyThread对象并启动它。然后,通过调用Thread.sleep()方法等待一段时间后,调用thread.interrupt()方法来中断线程。 通过这种方式,我们可以在循环内部检查中断请求并优雅地让线程退出循环,从而中断线程的执行。 ### 回答3: 在线程使用死循环是为了让线程一直执行某个任务,但有时候我们需要中断这个线程,停止它的执行。下面是一种常见的在线程中写死循环后中断线程的方法: 通常,我们会使用一个boolean类型的变量来标识线程是否继续执行循环。在外部想要中断线程时,我们将这个变量设置为false,从而使线程退出循环。 具体步骤如下: 1. 在线程的类中定义一个boolean类型的成员变量,例如isRunning,并初始化为true。 2. 在线程的run方法中使用while循环,并检查isRunning的值是否为true,如果是则继续执行循环。 3. 当外部需要中断线程时,通过调用线程对象的interrupt()方法发送中断信号给线程。 4. 在线程的run方法中的while循环中,检查线程中断状态,可以使用Thread类的静态方法Thread.interrupted()来检查中断状态,如果检查到中断状态为true,则退出循环。 5. 循环结束后,线程终止执行。 示例代码如下: ```java public class MyThread extends Thread { private volatile boolean isRunning = true; @Override public void run() { while (isRunning) { // 执行线程任务的代码 if (Thread.interrupted()) { // 检查线程中断状态 break; } } // 线程结束执行 } public void stopRunning() { isRunning = false; } } ``` 在外部代码中,我们可以通过调用线程对象的stopRunning()方法来中断线程: ```java public class Main { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); // 一段时间后中断线程 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } thread.stopRunning(); } } ``` 这样,当调用stopRunning()方法后,线程的isRunning变量将被设置为false,从而让线程退出死循环,实现了中断线程的目的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值