大厂面试题第 2 季—周阳—尚硅谷

视频链接

一.:前提说明 + 要求(1~1)

二.:Java 基础:

三.:JUC 多线程 及 高并发(2~)

( java.util.concurrent ) --> ( Java并发包 )
在这里插入图片描述

1_1:volatile__介绍:

   1)volatile 是 Java 虚拟机提供的一种,轻量级的同步机制
(可以理解为:乞丐版的 synchronized)
    (三大特性)
    -1:保证 可见性:
    -2:不保证 原子性:
    -3:禁止 指令重排序:


1_2:volatile__JMM 你谈谈:(Java 内存模型)

(Java Memory Model)(线程安全性,获得保证)
   1)JMM—可见性:(Java 内存模型)
    -1:JMM 解释:
在这里插入图片描述
    -2:JMM 关于同步的规定:
1:线程加锁前:必须读取主内存的最新值,到自己的工作内存。
2:线程解锁前:必须把共享变量的值,刷新回主内存。
3:加锁、解锁 是同一把锁。

    -3:可见性问题产生:
在这里插入图片描述
    -4:课件详解:
在这里插入图片描述

    -5:JMM 中,(主内存 & 自己工作内存)交互:

1:主内存:硬件,8G。
2:主内存中,有 student 对象:age = 25。
3:三个线程同时操作:分别取出主内存数据(age = 25),变量拷贝到自己线程的工作内存中,各自做计算操作。
4:t1 线程,对 age 进行改变,age = 37,然后将 37 写回给主内存。
5:但是,t1 改变,主内存改变,t2、t3 线程,还不知道改变。
6:要将 主内存的改变,即时通知到其他线程,及时通知的情况,就叫为 JMM 内存模型中的 可见性。
在这里插入图片描述

    -6:可见性代码验证:

/**
 * @author zhangxudong@chunyu.me
 * @date 2022/4/15 8:40 上午
 */
public class MyVolatile {
   

    public static void main(String[] args) {
   
        
        MyData myData = new MyData();

        new Thread(() -> {
   
            System.out.println("开始修改变量值");
            try {
   
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
   
            }
            myData.addTo60();
            System.out.println("变量值修改完毕:number = " + myData.number);
        }).start();

        new Thread(() -> {
   
            while (myData.number == 0) {
   
                // 如果 number,没有添加 volatile 关键字,
                // 则此线程,不会看到数值,已经被修改为 60,
                // 会一直循环下去。
            }
            System.out.println("检测到:a==60,返回");
        }).start();
    }
}
class MyData {
   

    int number = 0; // 改变不可见

	// 增强了:主内存 和 个个线程之间的可见性。
//  volatile int number = 0;    

    public void addTo60() {
   
        this.number = 60;
    }
}



   2)JMM—原子性:
    -1:原子性指的是什么:
1:不可分割,完整性。
2:也即:某个线程正在做某个具体业务时,中间不可以被加塞或者被分割。
3:需要整体完整,要么同时成功,要么同时失败。

    -2:volatile 不保证原子性,案例演示:

public class VolatileAtomic {
   

    public static void main(String[] args) throws InterruptedException {
   

        MyDataAtomic atomic = new MyDataAtomic();

        for (int i = 0; i < 20; i++) {
   
            new Thread(() -> {
   
                for (int j = 0; j < 1000; j++) {
   
                    atomic.addOne();
                }
            }).start();
        }
        // 所有线程计算停止后,才会取值展示
        while (Thread.activeCount() > 2) {
   
            Thread.yield();
        }
        System.out.println(atomic.number);  // 18888
    }
}
class MyDataAtomic {
   

    volatile int number = 0;

    public void addOne() {
   
    	// 在多线程下,线程不安全
        number++;
    }
}

    -3:解释:Volatile 不保证原子性:(number++;)
在这里插入图片描述
(从 虚拟机认识的,字节码文件分析)
在这里插入图片描述

    -4:解决:不保证原子性问题:(保证:可见性 + 原子性)
(不建议加 :synchronized,杀鸡用牛刀)

/**
 * @author zhangxudong@chunyu.me
 * @date 2022/4/15 10:24 上午
 */
public class VolatileAtomic {
   

    public static void main(String[] args) throws InterruptedException {
   

        MyDataAtomic atomic = new MyDataAtomic();

        for (int i = 0; i < 20; i++) {
   
            new Thread(() -> {
   
                for (int j = 0; j < 1000; j++) {
   
                    atomic.addOne();    //n++
                    atomic.addatomic(); // 原子 ++
                }
            }).start();
        }
        // 所有线程计算停止后,才会取值展示
        while (Thread.activeCount() > 2) {
   
            Thread.yield();
        }
        System.out.println(atomic.number);  // 18888
        System.out.println(atomic.atomicIntegerNumber); // 20000
    }
}

class MyDataAtomic {
   

    volatile int number = 0;

    public void addOne() {
   
        number++;
    }

    AtomicInteger atomicIntegerNumber = new AtomicInteger(0);

    public void addatomic() {
   
        atomicIntegerNumber.incrementAndGet();
    }
}



   3)JMM—可见性、有序性:(指令重排)

    -1:有序性说明:
在这里插入图片描述
    -2:重排:例(1)
在这里插入图片描述
在这里插入图片描述
    -3:重排:例(2)
在这里插入图片描述
    -4:禁止指令重排序原理:
在这里插入图片描述
在这里插入图片描述


1_3:volatile__哪些地方使用过:

   1)(单例模式,在多线程环境下,可能存在的安全问题):
    -1:JUC 包里面,大规模使用。

   2)单例模式:DCL 代码:(双重检查锁机制)
    -1:但是:多线程下存在问题:
1:为了性能和效果,底层有指令重排序。
2:没有控制好指令重排序,就可能会出现异常情况。

public class chongpai1 {
   

    public static void main(String[] args) {
   
    
        for (int ni = 0; ni < 1000; ni++) {
   
            new Thread(() -> {
   
                // 1000 个线程,调用
                SingletonDemo.getSingletonDemo();
            }).start();
        }
    }
}

class SingletonDemo {
   
    private static SingletonDemo singletonDemo = null;

    private SingletonDemo() {
   
        System.out.println("使用构造方法");
    }

    public static SingletonDemo getSingletonDemo() {
   
        if (singletonDemo == null) {
   
            synchronized (SingletonDemo.class) {
   
                if (singletonDemo == null) {
   
                    singletonDemo = new SingletonDemo();
                }
            }
        }
        return singletonDemo;
    }
}

   3)单例模式:volatile 代码:(上面:DCL 模式的改进)
    -1:DCL 机制,不一定安全,因为有指令重排序的存在,加入 volitaile,可以禁止指令重排序。
    -2:DCL 分析:
在这里插入图片描述


2:CAS 你知道吗:( compareAndSwap )

   1)比较并交换( compareAndSwap ):代码案例:

AtomicInteger atomicInteger = new AtomicInteger(5);

/** 
 *  相当于 i++
 *  底层原理就是 CAS
 */
atomicInteger.getAndIncrement();

// 比较并交换
atomicInteger.compareAndSet(5, 100);	// 修改成功
atomicInteger.compareAndSet(6, 200);	// 修改失败

// 修改成功,输出100
System.out.println(atomicInteger.get());

   2)CAS 底层原理?Unsafe类的理解:
    -1:入门解释:(比较并交换)
(如果期望值与主内存的值一样,才会修改成功)

public static void main(String[] args) {
   

    AtomicInteger atomicInteger = new AtomicInteger(5);
    
    // 输出 true
    System.out.println(atomicInteger.compareAndSet(5, 100));
    // 输出 false
    System.out.println(atomicInteger.compareAndSet(5, 200));
    
    // 最终值:输出100
    System.out.println(atomicInteger.get());
}

在这里插入图片描述

    -2:AtomicInteger 底层代码:
【实现原子性原理:(CAS思想(自旋) + UnSafe 类 )】

UnSafe 类的路径(娘胎里就带的类)::/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/rt.jar!/sun/misc/Unsafe.class

在这里插入图片描述

    -3:UnSafe 类详解:
在这里插入图片描述
在这里插入图片描述

    -4:CAS 是什么:(自旋思想)
在这里插入图片描述
1:unsafe.getAndAndInt():翻看底层代码。
在这里插入图片描述
在这里插入图片描述

2:底层汇编语言:
在这里插入图片描述

3:简单版 小总结:
在这里插入图片描述


   3)CAS 缺点:
    -1:如果:CAS 一直失败,会一直循环进行尝试。如果 CAS 一直不成功,会给 CPU 带来很大的开销:
    -2:只能保证,一个共享变量的原子操作:多个变量,CAS 就不能保证操作原子性,需要加锁来保证。
    -3:会有 ABA 问题:


3:AutomicInteger 的 ABA 问题,,原子更新引用知道吗:

在这里插入图片描述
   1)ABA 问题产生原因:(狸猫换太子)
(只比较了开头和尾巴,没有管中间的操作。中间可能被操作过。)
在这里插入图片描述
在这里插入图片描述

/**
 * ABA 问题的产生
 */
public class MyABA {
   

    public static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);

    public static void main(String[] args) {
   

        // 100 -> 101 -> 100
        new Thread(() -> {
   
            atomicReference.compareAndSet(100, 101);
            atomicReference.compareAndSet(101, 100);
        }, "t1").start();

        // 100 -> 1029,虽然 100 这个值,被其他线程变动,
        // 但比较 100 = 100,仍然会修改成功
        new Thread(() -> {
   
            // 暂停 1s,保证上面的 t1 线程完成 ABA 运算
            try {
   
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
   
            }
            atomicReference.compareAndSet(100, 2019);
            System.out.println(atomicReference.get());
        }, "t2").start();
    }
}

   2)原子引用:

public static void main(String[] args) {
   

    User z3 = new User("z3", 15);
    User l4 = new User("l4", 17);
    
    AtomicReference<User> userAtomicReference = new AtomicReference<>();
    userAtomicReference.set(z3);
    
    userAtomicReference.compareAndSet(z3, l4);
    System.out.println(userAtomicReference.get());
    
    // 此时主内存值,已经被替换为 l4,比较并交换失败。
    userAtomicReference.compareAndSet(z3, l4);
    System.out.println(userAtomicReference.get());
}

   3)版本号 原子引用:(解决 ABA 问题)

/**
 * ABA 问题的解决
 */
public class MyABA22 {
   
    
    public static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);

    public static void main(String[] args) {
   

        new Thread(() -> {
   
            // 获取第一次版本号
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + ":第一次版本号:" + stamp);// t1:第一次版本号:1
            // 暂停 1s,保证,t1,t2 拿到的第一次版本号相同。
            try {
    TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {
    }

            // ABA 问题产生
            atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + ":第二次版本号:" + atomicStampedReference.getStamp());// t1:第二次版本号:2
            atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp(
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用中的内容是一个使用Jedis连接Redis的示例代码。在这个示例中,首先创建一个Jedis对象,并指定Redis服务器的IP地址和端口号。然后通过调用jedis.ping()方法来测试与Redis服务器的连通性。最后使用jedis.set()方法将一个键值对存储到Redis中,***这些数据不需要固定的模式,并且可以进行横向扩展。这意味着Redis可以处理这些非结构化的数据,并且能够支持高并发的访问。 引用指出大多数企业使用Linux版的Redis,而Windows版只适用于学习。在使用Redis之前,需要在命令行窗口中启动Redis服务端。然后可以使用redis-cli.exe命令连接到Redis服务器,并进行一系列的操作,如设置键值对、获取键值对等。 关于"尚硅谷周阳redis"这个提到的名字或词组,我在提供的引用内容中没有找到具体的相关信息。请提供更多的上下文或细节,我将尽力提供有关此主的答案。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Redis—尚硅谷—周阳](https://blog.csdn.net/qq_43056248/article/details/118355838)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Redis学习笔记(转尚硅谷周阳)](https://blog.csdn.net/m0_58779356/article/details/119740018)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值