线程的中断

线程的中断

线程在调度过程中,可能会发生中断情况,而线程中断的本质原因只有一个:线程入口方法执行完毕!
在=观察线程中断的过程中。我们可以人为添加线程结束位置。

//线程中演示
//使用lambda表达式
public class ThreadDome6 {
    private static boolean on_off = true;
    public static void main(String[] args) {
        //创建一个线程
        Thread t = new Thread(()->{
            while (on_off){
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        //3秒后终止线程
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        on_off = false;
    }
}

在这里插入图片描述

这个是正常结束一个线程。

上图代码我们使用成员变量对线程时间作为分析,能不能试试将成员变量改成局部变量呢?

答案是:不能!

这里线程可以中断的原因是因为lambda表达式的——变量捕获,变量捕获指的是lambda表达式中使用的变量一定是由final、或者实际final所修饰(变量的值不曾修改过)。否则就会有语法错误。
接下来介绍thread内置方法中断循环,其实在Thread内部包含了一个Boolean类型的属性作为线程是否被中断的标记。

public class ThreadDome7 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            //currentThread()获取当前thread实例(t)
            //isInterrupted()就是t自带的标志位
            while (!Thread.currentThread().isInterrupted()){
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //改变标志位为flase,注意这里和上面的是不一样的
        t.interrupt();
        System.out.println("线程结束");
    }
}

currentThread():获取当前线程实例

isInterrupted():实例中带有的标志位

在main方法中改变t的标志位,线程中断。

在这里插入图片描述

可是这里打印了一个错误信息,线程也没有正常中断。
根据错误信息定位,发现其中sleep执行了一个操作,该操作使得sleep在休眠时被强制唤醒,sleep会将标志位清空,将本来应该是false的标志位改成true,所以线程才可以继续运行,而正因为将标示位清空,系统也找不到中断标志,在这个案例中也就无法停止。

多个线程之间的中断

这里介绍main线程和thread线程之间的中断。
其实线程的执行不是从上到下,而每个线程都是独立的存在,基本上不会相互影响,除非在调度过程中两个线程不断被调度,这有时候会导致:线程的等待。
线程的等待
当继承中资源不足或者在调度其他线程时,一些线程就会存在等待现象,也称为阻塞,这里我们通过调用join方法来实现线程阻塞!

1.main调用(线程.join)方法,线程此时在执行中,则main线程出现阻塞现象,直到线程完成执行状态,main才得以继续运行。

public class ThreadDome8 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            while(true){//死循环,这里也可以设置向上面代码一样设置停止时间
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("hello main");
    }
}

​ 2.main调用(线程.join)方法,线程此时已经结束,main继续运行。

public class ThreadDome8 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            System.out.println("hello t");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t.start();
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("hello main");
    }
}

添加join方法中可以设置等待时间!
**添加参数:**规定等待时间,增加程序的可控性!
**不添加参数:**相当于‘死等’,你不会知道线程结束的时机,不可控!

线程的三种状态

new:系统中有一个线程对象
running:线程处于就绪状态,随时可以被调度
terminated:线程执行完毕,系统中对象存在。

线程十分方便,多个线程会经常出现线程的不安全!!是因为线程之间调度的顺序是不确定的,举个栗子🌰:

//对两个线程分别进行1w次自增操作
class Counter{
    private static int count;

    public static int getCount() {
        return count;
    }

    public void add(){
        count++;
    }
}
public class ThreadDome9 {
    public static void main(String[] args) {
        Counter counter = new Counter();
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 10000 ; i++) {
                counter.add();
            }
        });
        Thread t2 = new Thread(()->{
            for (int i = 0; i < 10000; i++) {
                counter.add();
            }
        });
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Counter.getCount());
    }
}

打印:在这里插入图片描述

在这里插入图片描述
线程安全值得我们注意,调度线程可能会引发一些问题,像操作系统中的死锁!这就是系统调用不安全造成的一个bug。解决bug的方法:1.将两个线程分开执行。2.添加锁定操作,当两个线程需要并发执行时,将变量更改!

  • 12
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值