JUC——补充篇
面试🤺🤺🤺<持续更新
>
- 🗡️JAVA
- ⚔️ Java基础篇
- ⚔️ I/O、泛型、反射、异常篇
- ⚔️ Java容器篇
- ⚔️ JUC
- ⚔️ JVM
- ⚔️ 新特性
- ⚔️ 补充点
⚔️ JUC补充篇
- 前言
- 一、🕐 单例模式的双重校验锁
- 二、🕐 消费者-生产者的虚假唤醒
- 总结
前言
通过本文,你将了解如下内容:
- 🕐 单例模式的双重校验锁
- 🕑 消费者-生产者的虚假唤醒
- 🕒 面向对象基础
- 🕓 Java语言常用类拥有那些方法
穿插在文章内的补充知识点(希望也能看看,说不定有不一样的收获❤️❤️❤️)`
提示:以下是本篇文章正文内容
一、🕐 单例模式的双重校验锁
/* @desc Singleton 懒汉式* @author lanan* @date 2022-08-04 17:25:42/
class Singleton {private static Singleton singleton;private Singleton() {}public static Singleton getSingleton() {if (singleton != null) {singleton = new Singleton();}return singleton;}
}
以上写法在多线程情况下可能产生的问题:
- 没有做同步处理,每次都会new一个singleton对象去替换掉原singleton对象
- singleton = new Singleton();操作可能会发生指令重排
– 1、为singleton分配内存
– 2、链接的准备阶段赋默认值
– 3、将new Singleton()堆中地址赋给singleton
正常执行是1=>2=>3,如果发生指令重排,可能导致执行顺序变成1=>3=>2解决办法,使用synchronized保证同步,再使用双重校验锁优化锁的粒度,再使用volatile禁止指令重排
/* @desc Singleton 双重校验锁 + volatile* @author lanan* @date 2022-08-04 17:35:48/
class Singleton {private volatile static Singleton singleton;private Singleton() {}public static Singleton getSingleton() {if (singleton == null) {synchronized (Singleton.class) {if (singleton == null) {singleton = new Singleton();}}}return singleton;}
}
二、🕐 消费者-生产者的虚假唤醒
- 实现先慢慢的看一下代码,代码的目的就是输出1和0,但结果却超出了这个范围,原因是在if判断里面进入了wait状态,进入wait状态之前进行了条件判断,当被唤醒后,不会再去校验本次是否符合if判断条件,而是直接执行下面操作(注意:线程从wait状态唤醒,会继续执行之前操作):
- eg:A为-1操作线程、B为-1操作线程、C为+1操作线程、D为+1操作线程
– A、B当number为0,进入等待,否则-1并执行notifyAll
– C、D当number不为0,进入等待,否则+1并执行notifyAll
– 多线程情况下,假设一种场景,执行C,number=1;再执行C、D,两种都进入阻塞;此时执行A,number=0,C、D被唤醒;依次执行C、D,执行C,number=1,执行D,从wait处继续执行,number=2,出现不应该出现的数字了
– 原因:D唤醒后,number=1,应该再次进入wait,但if不具备再次校验
– 解决:将if改为while,唤醒后再次判断是否符合条件
/* 线程之间的通信问题:生产者和消费者问题! 等待唤醒,通知唤醒* 线程交替执行 A B 操作同一个变量 number = 0* A number + 1* B number - 1* @author LanAn* @date 2022/8/4-17:03*/
public class MainTest {public static void main(String[] args) {Test t = new Test();new Thread(()->{for (int i = 0; i < 10; i++) {try {t.increment();} catch (InterruptedException e) {e.printStackTrace();}}},"A").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {t.decrement();} catch (InterruptedException e) {e.printStackTrace();}}},"B").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {t.increment();} catch (InterruptedException e) {e.printStackTrace();}}},"C").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {t.decrement();} catch (InterruptedException e) {e.printStackTrace();}}},"D").start();}
}// 判断等待,业务,通知
class Test{ // 数字 资源类private int number = 0;//+1public synchronized void increment() throws InterruptedException {if (number!=0){ //0// while (number!=0){ // 0// 等待this.wait();}number++;System.out.println(Thread.currentThread().getName()+"=>"+number);// 通知其他线程,我+1完毕了this.notifyAll();}//-1public synchronized void decrement() throws InterruptedException {if (number==0){ // 1// while (number==0){ // 1// 等待this.wait();}number--;System.out.println(Thread.currentThread().getName()+"=>"+number);// 通知其他线程,我-1完毕了this.notifyAll();}}
总结
资料来源:
- guide哥.【JavaGuide】. 面试指南. JAVA,.