JavaEE初阶 多线程 3

volatile关键字

上个博客说过造成线程安全问题还有一个可解决的原因,内存可见性

volatile 修饰的变量,能够保证"内存可⻅性"

java 复制代码
  private static int flag=0;
    public static void main(String[] args) {
        Thread t0=new Thread(()->{
            while (flag==0){
                System.out.println("t0");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("t0结束");
        });
        Thread t1 = new Thread(() -> {
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入 flag 的值: ");
            flag = scanner.nextInt();
            System.out.println("t2 结束");
        });
        t0.start();
        t1.start();
    }

上述代码运行起来结果不会出现t0结束,原因就是t0进程的对flag的load取数指令被编译器优化掉了,while循环很快,每次读到flag的值相同,而load的开销相比于compare比较指令大多,因此被优化为cmp

当t1对flag变量进⾏修改,此时t0感知不到flag的变化

加volatile 关键字

java 复制代码
  private static volatile int flag=1;

结果:

wait 和notify

线程之间是抢占式执⾏的,因此线程之间执⾏的先后顺序难以预知,但可以让调度到该线程时使用wait使该线程阻塞等待,直到其他线程使用notify唤醒

wait()/wait(long timeout): 让当前线程进⼊等待状态.

notify() / notifyAll(): 唤醒在当前对象上等待的线程.

注 意 : wait,notify, notifyAll 都是 Object 类的⽅法

wait()⽅法 :

使当前执⾏代码的线程进⾏等待.(把线程放到等待队列中)

过程

1.释放当前的锁

2.满⾜⼀定条件时被唤醒

3.重新尝试获取这个锁

java 复制代码
Object locker = new Object();

 Thread t1=new Thread(()->{
   synchronized (locker) {
   System.out.println("等待中");
   locker.wait();
   System.out.println("等待结束");
   }
}

notify()⽅法:

1.唤醒等待的线程,如果有多个线程等待,则有线程调度器随机挑选出⼀个呈wait状态的线程。(并没有"先来后到")

2.在notify()⽅法后,当前线程不会⻢上释放该对象锁,要等到执⾏notify()⽅法的线程将程序执⾏ 完,也就是退出同步代码块之后才会释放对象锁。

java 复制代码
Thread t2=new Thread(()->{
synchronized (locker){
                System.out.println("notify之前");
                locker.notify();
                System.out.println("notify之后");
            }

notifyAll()⽅法: notify⽅法只是唤醒某⼀个等待线程.使⽤notifyAll⽅法可以⼀次唤醒所有的等待线程.

wait与sleep区别

1.wait是Object类中的一个方法,sleep是Thread类中的一个方法;

2.wait必须在synchronized修饰的代码块或方法中使用,sleep方法可以在任何位置使用;

3.wait被调用后当前线程进入BLOCK状态并释放锁,并可以通过notify和notifyAll方法进行唤醒;sleep被调用后当前线程进入TIMED_WAIT状态,不涉及锁相关的操作;

相关推荐
asdfg125896316 分钟前
一个例子通俗理解Java中正则表达式用法
java·正则表达式
一嘴一个橘子20 分钟前
MyBatis‑Plus Service 层常用自带方法
java
峥嵘life21 分钟前
Android16 系统 APEX 模块调试总结
android·大数据·开发语言
健康平安的活着23 分钟前
java中批量查询+stream返回map提高查询效率
java·windows·python
wear工程师24 分钟前
Spring 循环依赖为什么要三级缓存:两级会把 AOP 代理弄丢
java·spring
paopaokaka_luck26 分钟前
基于springboot3+vue3+uniapp的河南非遗数字图谱小程序(协同过滤算法、数字图谱展示、ECharts 图形化分析)
java·前端·spring boot·学习·小程序·uni-app·echarts
OPEN-F30 分钟前
C++进阶教程:类与对象深入
java·开发语言·c++
莫陌尛.30 分钟前
StarRocks Iceberg MinIO S3 301报错完整修复文档(Docker环境)
java·docker·容器
AI人工智能+电脑小能手31 分钟前
大白话说Java设计模式-42-访问者模式(业务实战篇)
java·spring·设计模式·访问者模式·asm·营销规则·数据结构与操作分离