JUC并发编程与源码分析学习笔记(二)

目录

二十九、多线程锁之线程锁知识概述

三十、多线程锁之悲观锁和乐观锁介绍

三十一、多线程锁之8锁案例编码演示

1、(代码)locks目录下:Lock8Demo.java

三十三、多线程锁之synchronized字节码分析

2、(代码)locks目录下:LockSyncDemo.java

三十四、多线程锁之synchronized底层原语分析

三十五、多线程之公平锁和非公平锁

三十六、多线程锁之可重入锁理论知识

三十七、多线程锁之可重入锁synchronized代码验证

3、(代码)locks目录下:ReEntryLockDemo.java

三十八、多线程锁之可重入锁原理分析和lock代码验证

三十九、多线程锁之死锁案例和排查命令

4、(代码)locks目录下:DeadLockDemo.java

四十、多线程锁之objectMonitor和synchronized锁小总结

四十一、中断机制之中断协商机制简介

四十二、中断机制之3大中断方法说明

四十三、中断机制之通过volatile实现线程中断停止

5、(代码)interrupt目录下:InterruptDemo.java

四十四、中断机制之通过AtomicBoolean实现线程中断停止

四十五、中断机制之通过interrupt实现线程中断停止

四十六、中断机制之interrupt和isInterrupted源码分析

四十七、中断机制之中断协商案例深度解析-上集

6、(代码)interrupt目录下:InterruptDemo2.java

四十八、中断机制之中断协商案例深度解析-下集

7、(代码)interrupt目录下:InterruptDemo3.java

四十九、中断机制之静态方法interrupted

8、(代码)interrupt目录下:InterruptDemo4.java

五十、LockSupport之是什么及等待唤醒机制对比

五十一、LockSupport之wait和notify实现等待和唤醒

9、(代码)LockSupport目录下:LockSupportDemo.java

五十二、LockSupport之await和signal实现等待和唤醒

五十三、LockSupport之park和unpark入门简介

五十四、LockSupport之park和unpark编码实战


二十九、多线程锁之线程锁知识概述

说说Java“锁”事

从轻松的乐观锁和悲观锁开讲

通过8种情况演示锁运行案例,看看我们到底锁的是什么

公平锁和非公平锁

可重入锁(又名递归锁)

死锁及排查

写锁(独占锁)/读锁(共享锁)

自旋锁SpinLock

无锁->独占锁->读写锁->邮戳锁

无锁->偏向锁->轻量锁->重量锁

大厂面试题复盘

并发编程高级面试解析

一、Synchronized相关问题

1、Synchronized用过吗,其原理是什么?

2、你刚才提到获取对象的锁,这个“锁”到底是什么?如何确定对象的锁?

3、什么是可重入性,为什么说Synchronized是可重入锁?

4、JVM对Java的原生锁做了哪些优化?

5、为什么说Synchronized是非公平锁?

6、什么是锁消除和锁粗化?

7、为什么说Synchronized是一个悲观锁?乐观锁的实现原理又是什么?什么是CAS,它有

8、乐观锁一定就是好的吗?

二、可重入锁ReentrantLock及其他显示锁相关问题

1、跟Synchronized相比,可重入锁ReentrantLock其实现原理有什么不同?

2、那么请谈谈AQS框架是怎么回事儿?

3、请尽可能详尽地对比下Synchronized和ReentrantLock的异同。

4、ReentrantLock是如何实现可重入性的?

1、你怎么理解java多线程的?怎么处理并发?线程池有那几个核心参数?

2、Java加锁有哪几种锁?我先说了synchronized,刚讲到偏向锁,他就不让我讲了

3、简单说说lock

4、hashmap的实现原理?hash冲突怎么解决?为什么使用红黑树?

5、spring里面都使用了哪些设计模式?循环依赖怎么解决?

6、项目中哪个地方用了countdownlatch,怎么使用的?

三十、多线程锁之悲观锁和乐观锁介绍

悲观锁(狼性锁):认为自己在使用数据的时候一定有别的线程来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改

synchronized关键字和Lock的实现类都是悲观锁

适合写操作多的场景,先加锁可以保证写操作时数据正确。

显示的锁定之后再操作同步资源

乐观锁(佛系锁):认为自己在使用数据时不会有别的线程修改数据或资源,所以不会添加锁。

在Java中是通过使用无锁编程来实现,只是在更新数据的时候去判断,之前有没有别的线程更新了这个数据。

如果这个数据没有被更新,当前线程将自己修改的数据成功写入。

如果这个数据已经被其它线程更新,则根据不同的实现方式执行不同的操作,比如放弃修改、重试抢锁等等

判断规则

1 版本号机制Version

2 最常采用的是CAS算法,Java原子类中的递增操作就通过CAS自旋实现的。

适合读操作多的常见,不加锁的特点能够使其读操作的性能大幅度提升。

乐观锁则直接去操作同步资源,是一种无锁算法,得之我幸不得我命,再努力就是一句话:

乐观锁一般有两种实现方式

采用Version版本号机制

CAS(Compare-and-Swap,即比较并替换)算法实现

伪代码说明

三十一、多线程锁之8锁案例编码演示

【强制】高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。

1、(代码)locks目录下:Lock8Demo.java

package com.nanjing.juc.locks;

import java.util.concurrent.TimeUnit;

/**
 * 多线程锁之8锁案例编码演示
 *
 * @author xizheng
 * @date 2023-08-14 15:22:42
 */
class Phone{
    public static synchronized void sendEmail(){
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("-----sendEmail");
    }

    public static synchronized void sendSMS(){
        System.out.println("-----sendSMS");
    }

    public void hello(){
        System.out.println("------hello");
    }
}

/**
 * 题目:谈谈你对多线程锁的理解,8锁案例说明
 * 口诀:线程   操作  资源类
 * 8锁案例说明:
 * 1 标准访问有ab两个线程,请问先打印邮件还是短信
 * 2 sendEmail方法中加入暂停3秒钟,请问先打印邮件还是短信
 * 3 添加一个普通的hello方法,请问先打印邮件还是hello
 * 4 有两部手机,请问先打印邮件还是短信
 * 5 有两个静态同步方法,有1部手机,请问先打印邮件还是短信
 * 6 有两个静态同步方法,有2部手机,请问先打印邮件还是短信
 * 7 有1个静态同步方法,有1个普通同步方法,有1部手机,请问先打印邮件还是短信
 * 8 有1个静态同步方法,有1个普通同步方法,有2部手机,请问先打印邮件还是短信
 *
 * 笔记总结:
 * 1-2
 * *  * 一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,
 * *  * 其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一的一个线程去访问这些synchronized方法
 * *  * 锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的synchronized方法
 * 3-4
 * *  * 加个普通方法后发现和同步锁无关
 * *  * 换成两个对象后,不是同一把锁了,情况立刻变化。
 *
 * 5-6 都换成静态同步方法后,情况又变化
 * 三种 synchronized 锁的内容有一些差别:
 * 对于普通同步方法,锁的是当前实例对象,通常指this,具体的一部部手机,所有的普通同步方法用的都是同一把锁->实例对象本身,
 * 对于静态同步方法,锁的是当前类的Class对象,如Phone.class唯一的一个模板
 * 对于同步方法块,锁的是 synchronized括号内的对象
 *
 * 7-8
 *    当一个线程视图访问同步代码时它首先必须得到锁,正常退出或抛出异常时必须释放锁。
 * *  *
 * *  * 所有的普通同步方法用的都是同一把锁-实例对象本身,就是new出来的具体实例对象本身,本类this
 * *  * 也就是说如果一个实例对象的普通同步方法获取锁后,该实例对象的其他普通同步方法必须等待获取锁的方法释放锁后才能获取锁。
 * *  *
 * *  * 所有的静态同步方法用的也是同一把锁-类对象本身,就是我们说过的唯一模板Class
 * *  * 具体实例对象this和唯一模板Class,这两把锁是两个不同的对象,所以静态同步方法与普通同步方法之间是不会有竞态条件的
 * *  * 但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁才能获取锁。
 */
public class Lock8Demo {
    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone2 = new Phone();

        new Thread(() -> {
            phone.sendEmail();
        },"a").start();

        //暂停毫秒,保证a线程先启动
        try {
            TimeUnit.MILLISECONDS.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
//            phone.sendSMS();
//            phone.hello();
            phone2.sendSMS();
        },"b").start();
    }
}

三十三、多线程锁之synchronized字节码分析

synchronized有三种应用方式

8种锁的案例实际体现在3个地方

作用于实例方法,当前实例加锁,进入同步代码前要获得当前实例的锁;

作用于代码块,对括号里配置的对象加锁。

作用域静态方法,当前类加锁,进去同步代码前要获得当前类对象的锁;

从字节码角度分析synchronized实现

javap -c ***.class文件反编译

synchronized同步代码块

javap -c .\LockSyncDemo.class(文件反编译)

synchronized同步代码块:实现使用的是monitorenter和monitorexit指令

synchronized普通同步方法

synchronized普通同步方法:调用指令将会检查方法的ACC_SYNCHRONIZED访问标志是否被设置。如果设置了,执行线程会将先持有monitor锁,然后再执行方法,最后在方法完成(无论是正常完成还是非正常完成)时释放monitor

synchronized静态同步方法

ACC_STATIC,ACC_SYNCHRONIZED访问标志区分该方法是否静态同步方法

2、(代码)locks目录下:LockSyncDemo.java

package com.nanjing.juc.locks;

/**
 * 锁同步演示
 *
 * @author xizheng
 * @date 2023-08-14 16:45:14
 */
public class LockSyncDemo {

    Object object = new Object();

    /**
     * monitorenter代表锁监视器获得了并进入
     *
     * 正常执行完毕以后会有
     * monitorexit说明要退出
     * synchronized的底层是依赖monitorenter和monitorexit来保证锁的获取和释放
     */
    public void m1(){
        synchronized (object){
            //也就是说这行代码,只要哪一个线程持有这把锁了,谁持有谁进来,进来以后干活,用完以后再将其释放
            System.out.println("----hello synchronized code block");
            //throw new RuntimeException("------exp");
        }
    }

    public synchronized void m2(){
        System.out.println("----hello synchronized m2");
    }

    public static synchronized void m3(){
        System.out.println("----hello static synchronized m3");
    }

    public static void main(String[] args) {

    }
}

三十四、多线程锁之synchronized底层原语分析

反编译synchronized锁的是什么

面试题:为什么任何一个对象都可以成为一个锁

什么是管程monitor

大厂面试题讲解

【Java集合类】

1、从集合开始吧,介绍一下常用的集合类,哪些是有序的,哪些是无序的

2、hashmap是如何寻址的,哈希碰撞后是如何存储数据的,1.8后什么时候变成红黑树、说下红黑树,红黑树有什么好处

3、concurrenthashmap怎么实现线程安全,一个里面会有几个段segment,jdk1.8后有优化concurrenthashmap吗?分段锁有什么坏处

【多线程JUC】

4、reentrantlock实现原理,简单说下aqs

5、synchronized实现原理,monitor对象什么时候生成的?知道mnitor的monitorenter和monitorexit这两个是怎么保证同步的吗?或者说,这两个操作计算机底层是如何执行的

6、刚刚你提到了synchronized的优化过程,详细说明一下吧。偏向锁和轻量级锁有什么区别?

7、线程池几个参数说下,你们项目中如何根据实际场景设置参数的,为什么cpu密集设置的线程数集型少

什么是管程monitor

在HotSpot虚拟机中,monitor采用ObjectMonitor实现

上述C++源码解读

ObjectMonitor.java->ObjectMonitor.cpp->objectMonitor.hpp

objectMonitor.hpp

每个对象天生都带着一个对象监视器

每一个被锁住的对象都会和Monitor关联起来

提前剧透,混个眼熟

synchronized必须作用域某个对象中,所以Java在对象的头文件存储了锁的相关信息。锁升级功能主要依赖于MarkWord中的锁标志位和释放偏向锁标志位,后续讲解解锁升级时候我们再加深,目前为了承前启后的学习,对下图先混个眼熟即可

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值