> 文章列表 > JUC——补充篇

JUC——补充篇

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,.