晋中建设集团有限公司网站,网站建设公司四川,科技成就,wordpress otp文章目录 前言一、今天学习了什么#xff1f;二、关于问题的答案1.线程池2.synchronized关键字3、volatile 总结 前言
提示#xff1a;这里为每天自己的学习内容心情总结#xff1b;
Learn By Doing#xff0c;Now or Never#xff0c;Writing is organized thinking.
… 文章目录 前言一、今天学习了什么二、关于问题的答案1.线程池2.synchronized关键字3、volatile 总结 前言
提示这里为每天自己的学习内容心情总结
Learn By DoingNow or NeverWriting is organized thinking.
好久没打卡了我真的是个垃圾我要认真学习。
加油加油啊 提示以下是本篇文章正文内容
一、今天学习了什么
最近学习的都是 JUC 相关的内容主要是两大块线程池和AQS。
线程池synchronizedAQSReentrantLock
二、关于问题的答案
1.线程池
为什么需要线程池呢什么是线程池
线程池是为了解决频繁的创建和销毁线程所带来的性能损耗当任务到达线程池后可以立马被线程执行任务并且线程是稀缺资源不能频繁的创建如果线程数大于CPU的核心数会导致频繁的上下文切换影响性能。
线程池是存储了一批已经创建好的线程可以被重复使用去执行任务。
线程池的参数 corePoolSize、maxPoolSize、阻塞队列、超时时间、超时时间的单位、线程工厂、拒绝策略。
当任务达到线程后的执行流程
首先判断线程池中的线程数和最大核心线程数的关系如果当前线程数小于最大核心线程数创建新的核心线程去执行任务如果线程池中的线程数和最大核心线程数相等那么判断阻塞队列是否已满阻塞队列未满将线程放入阻塞队列中等待阻塞队列已满判断线程池中的线程数和线程池最大线程数的关系如果小于最大线程数创建一个非核心线程去执行任务如果已经达到最大线程数那么需要根据线程池中的拒绝策略去对线程任务进行相应的处理。 饱和策略
有四种
直接拒绝抛出异常后拒绝让当前线程去执行这个任务丢弃阻塞队列中等待最久的任务将新的任务放入阻塞队列中等待。
2.synchronized关键字
请你介绍一下synchronized关键字 synchronized关键字是悲观锁的思想属于独占锁是通过JVM实现的。 让同一时刻保证只有一个线程能够占用锁资源其它想要获取共享资源的线程都会被阻塞住。 保证在代码块内即使出现异常也能正确释放锁资源。
synchronized的底层实现原理
在 JDK 1.6 以前synchronized关键字加锁方式被称之为重量级锁但是经过了优化引入了可偏向锁和轻量级锁synchronized的性能提升了很多。
Java创建对象的工作是由JVM来实现的对象的内存布局分为三部分对象头、实例数据、对齐填充对象头由两部分组成mark word 和 class pointer。在 mark word 中记录对象的hashcode、age、state而synchronized关键字的锁机制对应的就是mark word 中锁标志位的四种状态变化。
首先介绍重量级锁之所以称之为是重量级锁是因为在操作系统的底层被synchronized关键字修饰的对象都关联了一个Monitor管程通过mark word 指向管程引用。同一个对象的管程是同一个。
不加 synchronized 就不会关联 monitor 对象。
管程是一种特殊的数据结构可以确保只有一个活动线程能成为占用者由三部分组成owner、entryList、waitSet。
当线程占用锁资源会成为管程的owner对象并将线程指向该管程的 owner 引用。
并且在重量级锁实现了自旋优化想要获取锁资源的线程在获取失败后会自选通过CAS再尝试去获取锁资源。
JDK 6 之后自旋锁是自适应的是由 JVM 自己实现的不属于我们的控制范围。
轻量级锁
由于每次都需要关联操作系统的 monitor 对象使用成本很高所以在 JDK 1.6 之后进行了优化引入了 轻量级锁。
轻量级锁适用于有多线程去访问共享资源但是不会在同一时刻发生竞争如果在同一时刻发生竞争轻量级锁会升级为重量级锁。
JVM 会在每个方法执行时创建栈帧当代码执行到 synchronized 代码块时会在栈帧中创建 lock record 对象lock record 中有两个重要的属性分别是内存地址和对象引用。
使用 CAS 尝试将 对象头的mark word 和 lock record 中的内存地址交换并且将 lock record 的对象引用指向对象这就是轻量级锁加锁的方式使用 CAS 。
如果加锁失败可能有两种情况
出现了其他线程同时竞争共享资源出现锁膨胀锁升级为重量级锁出现了锁重入的情况就会在栈帧中再次创建一个 lock record 对象只不过这个 lock record 对象的内存地址为null对象引用指向共享资源
可偏向锁
由于轻量级锁即使当前线程已经获取到了共享资源发生重入时仍需要使用 CAS 比较浪费性能。
可偏向锁是在线程第一次获取到共享资源时使用 CAS 将自己的线程 ID 设置到对象头中之后当线程需要访问共享资源时只需要比较对象头中的线程 ID 是否一致即可提高性能。
默认是打开可偏向锁的如果共享资源处于可偏向状态此时有其它的线程竞争共享资源可偏向锁会升级为轻量级锁。
3、volatile
说一下 volatile 关键字
被 volatile 关键字修饰的变量有两层含义一个是可见性一个是有序性。
底层是操作系统的内存屏障实现的当线程对被 volatile 关键字修饰的变量进行写操作时会添加写屏障读操作时会添加读屏障。
写屏障保证对共享变量的写入操作会立即同步到主存中并且保证共享变量写操作前的代码不会重排序到写操作后。
读屏障保证对共享变量的读操作总是读取内存中最新的数值保证读操作前的代码不会重排序到读操作之后。
可以通过 volatile CAS 实现无锁并发性能比较高单独使用 volatile 关键字适用于读多写少的场景。
volatile 关键字能保证原子性吗为什么不能保证原子性
不保证因为原子性的定义是指一个操作是不可中断的但是被 volatile 修饰的变量的写操作和读操作之间是可以被中断的意味着在读取或者修改 volatile 变量的过程中可能会有其他线程对这个变量进行修改。
如果需要保证原子性建议使用 synchronized 关键字或者 JUC 提供的工具类。 总结
提示这里对文章进行总结
明天需要继续复习学习 Redis 和 刷题还要做科研准备周四下午的组会。