当前位置: 首页 > news >正文

【JavaEE】-- 多线程(初阶)3

文章目录

  • 6.volatile 关键字
    • 6.1 volatile能保证内存可见性
      • 6.1.1 CPU层面
      • 6.1.2 Java层面
    • 6.2 volatile保证有序性
    • 6.3 volatile不保证原子性
  • 7. wait 和 notify
    • 7.1 wait()方法和notify()方法
    • 7.3 notifyAll()方法
    • 7.4 wait() 和 sleep() 的对比(面试题)

6.volatile 关键字

public class Demo_601 {
    static int flg = 0;
    public static void main(String[] args) {
        Thread t1 = new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "线程启动");
            while (flg == 0){
                //不停的循环。处理任务。
            }
            System.out.println(Thread.currentThread().getName() + "线程退出");
        },"t1");
        t1.start();


        Thread t2 = new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "线程启动");
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入一个非零的整数");
            flg = scanner.nextInt();
            System.out.println(Thread.currentThread().getName() + "线程退出");
        }, "t2");
        t2.start();
    }
}

输出结果:
在这里插入图片描述

t2线程正常结束,并且已经修改了flg变量的值,但是t1没有结束,整个进程也没有结束,结果不及预期,线程安全问题产生。

问题产生的原因:
在这里插入图片描述
在这里插入图片描述
对于线程t1来说,只是比较flg这个变量的值,从来都没有修改过,所以CPU认为,这个值永远也不会改变,从而也不会重新从内存中读取值。

为了提高运行效率这个值一般存在寄存器或CPU的缓存中。

在这里插入图片描述

在Java层面我们叫这块内存是寄存器,在JVM层面我们叫这块内存是工作内存。

在多线程的环境下,就会出现我们看到的这个问题,一个线程修改了另一个线程无法感知到的变量。

6.1 volatile能保证内存可见性

6.1.1 CPU层面

MESI(缓存一致性协议),可以理解为一种通知机制。
在这里插入图片描述
当所有的处理器没有修改共享变量时,各自的处理器只读取自已缓存中的值,从而提升效率。

当某一个处理器往主内存中写回数据的时候,让缓存中的值失效,通知其他处理器从主内存中重新获取新的值。

6.1.2 Java层面

内存屏障:作用是保证指令执行的先后顺序,从而保证内存可见性。
在这里插入图片描述
在这里插入图片描述
为变量加上volatile关键字进行修饰之后的输出结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.2 volatile保证有序性

用volatile修饰过的变量,由于前后有内存屏障,保证了指令的执行顺序,也可以理解为告诉编译器,不要进行指令重排。

6.3 volatile不保证原子性

volatile 和 synchronized 有着本质的区别.synchronized能够保证原⼦性,volatile保证的是内存可⻅性.

7. wait 和 notify

  1. wait 和 notify 是Object类中的方法,每个对象都可以调用这个方法
  2. 作用:安排线程的执行顺序。
    在这里插入图片描述

join 和 wait 是两种不同的操作,join是Thread类中的方法,wait 和 notify 是Object 类中的方法。

7.1 wait()方法和notify()方法

public class Demo_602 {
    public static void main(String[] args) {
        Object locker = new Object();
        Thread t1 = new Thread(()->{
            while (true) {
                System.out.println("调用wait()之前....");
                synchronized (locker){
                    try {
                        locker.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                System.out.println("wait()唤醒之后...");
                System.out.println("=====================");
            }
        });

        Thread t2 = new Thread(()->{
            while (true) {
                System.out.println("调用notify之前....");
                synchronized (locker){
                    locker.notify();
                }
                System.out.println("调用notify之后....");

                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        t1.start();
        t2.start();
    }
}

在这里插入图片描述

7.3 notifyAll()方法

在这里插入图片描述
notify()唤醒一个线程notifyAlI()唤醒所有线程,全都再去竞争锁资源。

总结:

  1. wait 和 notify 必须搭配synchronized 一起使用。
  2. wait 和 notify 使用的锁对象必须是同一个。
  3. notify 执行多少次都没有关系(即使没有线程在wait)

7.4 wait() 和 sleep() 的对比(面试题)

其实理论上wait和sleep完全是没有可⽐性的,因为⼀个是⽤于线程之间的通信的,⼀个是让线程阻塞⼀段时间,唯⼀的相同点就是都可以让线程放弃执⾏⼀段时间.

当然为了⾯试的⽬的,我们还是总结下:

  1. wait需要搭配synchronized使⽤.sleep不需要,join也不需要(join是类中的方法)。
  2. wait是Object的⽅法sleep是Thread的静态⽅法.

相关文章:

  • DeepSeek-R1 如何凭联网优势登顶智创聚合 API 模型使用榜首
  • Windows 10 远程桌面连接使用指南
  • 分光器的光衰计算公式。
  • Angular Loss论文理解
  • 特别呈献:AIGC生图超现实VR全景特辑
  • 【算法】3302. 表达式求值
  • 如何在 ArcGIS Pro 中将SHP转为KML:详细步骤与操作指南
  • 如何把图片或者图片地址存到 MySQL 数据库中以及如何将这些图片数据通过 JSP 显示在网页中
  • 2 Redis 字符串(String) 命令大全
  • ISP CIE-XYZ色彩空间
  • Keil5 MDK使用记录
  • 【Java项目】基于SpringBoot的广场舞团管理系统
  • 华为开源自研AI框架昇思MindSpore应用案例:基于MindSpore框架实现one-stage目标检测模型SSD
  • 解锁责任链模式:Java 实战与应用探秘
  • 人工智能之数学基础:矩阵的范数
  • 样式和ui(待更新)
  • 【TI毫米波雷达】DCA1000的ADC原始数据C语言解析及FMCW的Python解析2D-FFT图像
  • Git与GitHub:它们是什么,有什么区别与联系?
  • 软件测试学习1
  • threeJs+vue 加载gltf模型、获取模型尺寸、播放模型动画
  • 网站上传小马后怎么做/搜索引擎优化方式
  • 县局网站建设招标/成都网站改版优化
  • 多用户智能网站建设源码/seo销售代表招聘
  • 网站如何使用cdn/流量精灵官网
  • iis做网站的流程/百度网盟推广
  • 海外网购/seo属于技术还是营销