线程的中断与等待

中断一个线程

让线程停下来,也可以成为线程终止
本质来说,让线程终止,办法有 且只有一种,,就是让该线程的入口方法执行完毕。
1.设置一个标志位

public class ThreadDemo1 {
    public static boolean= false;
    public static void main(String[] args) {
        //boolean isQuit = false;
        Thread t = new Thread(() -> {
            while (!isQuit){
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("t 线程终止");

        });

        t.start();
        //在线程在修改isQuit
        try {
            Thread.sleep(3000);//设置三秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        isQuit = true;
    }
}

只要循环条件不成立 自然就结束
比如我们定义了一个变量isQui 让我们的t1线程先跑,我们的主线程先休眠3000毫秒 时间一到就给改成true,条件不成立线程自然最终止
在这里插入图片描述
如果我们把成员变量改成局部变量 此时受变量捕获的影响 就会报错
java要求变量捕获 的对象必须是final或者实际final,然而我们没有用final
修饰但是代码中并没有修改
在这里插入图片描述
此时报错信息也告诉了我们
所以解决的办法就是
把isQuit改成成员变量
2.以下这个代码是通过并发执行的
t线程 和main线程各执行各的通过快速调度
t先执行3s 然后main执行 interrupt 此时t线程抛异常

public class ThreadDemo2 {
    public static void main(String[] args) {
        //currentThredd 是获取当时线程的实例
        //此处currentThredd 得到对象t
        //isInterrupted 就是 t 里面自带一个标准位

        Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()){
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                  //  break;
                }
            }
        });
        t.start();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //把内部标志设成ture
        t.interrupt();

    }
}

在这里插入图片描述
interrupt方法作用
1.设置标志位为true
2.如果该线程正在堵塞(比如正在执行sleep)此时就会把线程堵塞状态唤醒通过怕抛异常的方式让sleep立即结束
注意:当sleep被唤醒的时候sleep会自动把isInterrupted给清空 把ture改成false,这就导致下次循环依旧可以
3.如果我们想让线程结束循环此时就要在catch中手动加上一个break,此时问题就结束了

在这里插入图片描述
为什么sleep要清空标志位:目的就是为了让线程自身能够对线程何时结束,有一个明确的控制。
当前interrupt方法,效果不是让线程立即结束,而是告诉他你该结束了,至于他是否针对结束,立即结束还是等会结束都是通过代码控制的,这里我们要明白interrupt是通知而不是命令

等待一个线程join()

线程之间是并发执行的,操作系统对于线程的调度是无序的,无法判段两个线程那个先执行
来看一下案例
在这里插入图片描述
这个代码先执行谁我们是无法确定的,但是这个代码实际的执行情况大部分是先执行“hello main”(因为创建线程也有开销)
但是不排除特定情况下main还没有执行到

此时有一个方法可以实现线程等待 join方法
在这里插入图片描述
t.join执行还没结束的时候main线程就会堵塞等待,main线程中调用t.join意思是让mian线程等待t先执行完,再往下执行!!!
2. main线程调用t.join的时候如果t线程已经执行完了,此时join不会堵塞,就会立即往下执行。
以上两种都能保证t是先执行完的那个

此时还要注意 main堵塞了就不参与cpu调度了,此时只有t线程去执行了,也就谈不上并不并发。

注意;join有两个版本
无参数版本的,效果就是死等。
有参数版本的,则是指定最大超过时间,如果等待时间 上限了,还没等到,就不等了。

线程的状态

1.线程的所以状态:
NEW: 安排了工作, 还未开始行动
RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作.
BLOCKED: 这几个都表示排队等着其他事情
WAITING: 这几个都表示排队等着其他事情
TIMED_WAITING: 这几个都表示排队等着其他事情
TERMINATED: 工作完成了.
在这里插入图片描述
我们直接打印getState方法就可以查看线程的状态
在这里插入图片描述
一天主线三条支线分别代表不同的线程状态

多线程带来的线程安全问题

看代码

class Counter{
    public  int count = 0;
    public void add(){
        count++;
    }
    public int get(){
        return count;
    }
}
public class ThreadDemo5 {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        //搞两个线程分别对这个counter自增5w次
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                counter.add();
            }
        });
        Thread t2 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                counter.add();
            }
        });
        t1.start();
        t2.start();

        //等待两个线程执行结束 然后查看结果
        t1.join();
        t2.join();

        System.out.println(counter.get());
    }
}

上述代码是两个线程针对同一个变量各自自增5w次
预期结果是10w
在这里插入图片描述
我们的实际结果是随机值 而且每一次还不一样 为什么?
这其实就是由多线程引起的bug 线程不安全。
解释以下为什么会出现这种情况,和线程的调度随机性密切相关
其实我们的count++是由三部分组成的
1.load就是把内存中的值读到寄存器中
2.add,就是把寄存中的值进行+1
3.save,就是把寄存器中的值写会内存

由于多线程,调度是不确定
实际执行过程中的++操作实际有很多种可能

在这里插入图片描述

上述我们举了几个例子
此处这俩线程的指令的排序,(执行的先后)就会有很多种可能的排序情况,在排列顺序的不同情况下,执行结果,可能就是截然不同
所以里面很有有可能相互覆盖结果
所以归根结底,线程安全问题全是因为线程调度的无序,导致了执行顺序不确定,结果也就变化了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值