JUC——补充篇

面试🤺🤺🤺<持续更新>

  • 🗡️JAVA
    • ⚔️ Java基础篇
    • ⚔️ I/O、泛型、反射、异常篇
    • ⚔️ Java容器篇
    • ⚔️ JUC
    • ⚔️ JVM
    • ⚔️ 新特性
    • ⚔️ 补充点


前言

通过本文,你将了解如下内容:

  • 🕐 单例模式的双重校验锁
  • 🕑 消费者-生产者的虚假唤醒
  • 🕒 面向对象基础
  • 🕓 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;

    //+1
    public 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();
    }

    //-1
    public 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,.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝桉未与

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值