- 博客(75)
- 收藏
- 关注
![](https://csdnimg.cn/release/blogv2/dist/pc/img/listFixedTop.png)
原创 3.5、Monitor概念、synchronized原理、synchronized锁升级及实例(轻量级锁、重量级锁、自旋锁、偏向锁)
Monitor概念Java对象头以32位虚拟机为例普通对象数组对象其中Mark Word结构为64位虚拟机Mark Word参考资料https://stackoverflow.com/questions/26357186/what-is-in-java-object-header原理之Monitor(锁)Monitor被翻译为监视器或管程每个Java对象都可以关联一个Monitor对象,如果使用synchronized给对象上锁(重量级)之后,该对象头的Mark Work中
2022-03-06 03:13:22
453
原创 线程安全集合类概述
线程安全集合类可以分为三大类:遗留的线程安全集合如Hashtable,vector使用Collections装饰的线程安全集合Collections.synchronizedCollectionCollections.synchronizedListCollections.synchronizedMapCollections.synchronizedSetCollections.synchronizedNavigableMapCollections.synchronizedNaviga.
2022-05-16 01:03:39
417
原创 JUC-CyclicBarrier
循环栅栏,用来进行线程协作,等待线程满足某个计数,构造时设置【计数个数】,每个线程执行到某个需要“同步”的时刻调用await()方法等待,当等待的线程数满足【计数个数】时,继续执行CyclicBarrier barrier = new CyclicBarrier(2); new Thread(() -> { System.out.println("线程1开始" + new Date()); try { b
2022-05-16 00:54:10
131
原创 JUC-CountdownLatch
简介用来进行线程同步协作,等待所有线程完成倒计时。其中构造参数用来初始化等待计数值,await()用来等待计数归零,countDown()用来让计数减一public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(3); new Thread(() -> { log.debug("b
2022-05-16 00:33:51
159
原创 JUC-Semaphore
基本使用信号量,用来限制能通知访问共享资源的线程上限public static void main(String[] args) { Semaphore semaphore = new Semaphore(3); for (int i = 0; i < 10; i++) { new Thread(() -> { try { semaphore.acquire();
2022-05-15 15:06:17
196
原创 JUC-StampedLock
该类自JDK8加入,是为了进一步优化读性能,他的特点是在使用读锁、写锁时都必须配合【戳】使用加解读锁long stamp = lock.readLock();lock.unlockRead(stamp);加解写锁long stamp = lock.writeLock();lock.unlockWrite(stamp);乐观读,StampedLock支持typeOptimisticRead()方法(乐观读),读取完毕之后需要做一次戳校验,如果校验通过,表示这期间确实没有写操作,数据可以安全使
2022-05-15 14:21:05
2724
原创 JUC-读写锁ReentrantReadWriteLock
1、ReentrantReadWriteLock当读操作远远高于写操作时,这时候使用读写锁让读-读可以并发,提高性能。类似于数据库中的select ... from ... lock in share mode提供一个数据容器类分别使用读锁保护数据的read()方法,写锁保护数据的write()方法public class DataContainer { private Object data; private ReentrantReadWriteLock rw = new Reen
2022-05-04 15:05:47
702
原创 JUC-AQS(AbstractQueuedSynchronizer)原理
1、概述全称是AbstractQueueSynchronizer,是阻塞式锁和相关同步器工具的框架特点:用state属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁getState - 获取state状态setState - 设置state状态compareAndSetState - cas机制设置state状态提供基于FIFO的等待队列,类似Monitor的EntryList条件变量来实现等待、唤醒机制,支持多个条件变量,类似Mon
2022-03-27 23:43:21
686
原创 7、共享模型之工具 - 3、Fork/Join
3、Fork/Join1)概念Fork/Join是JDK1.7加入的新的线程池实现,它体现的是一种分治思想,适用于能够进行任务拆分的CPU密集型运算所谓的任务拆分,是将一个大任务拆分为算法上相同的小任务,直至不能呢个拆分可以直接求解。跟递归相关的一些计算,如归并排序、斐波那契数列,都可以用分支思想进行求解Fork/Join在分支的思想上加入了多线程,可以把每个任务分解和合并交给不同的线程来完成,进一步提升了运算效率Fork/Join默认会创建与CPU核心大小相同的线程池2)使用提交给Fork/
2022-03-26 23:16:46
456
原创 7、共享模型之工具 - 2、ThreadPoolExecutor
2、ThreadPoolExecutor1)线程池状态ThreadPoolExecutor使用int的高3位表示线程池状态,低29位表示线程数量状态名高3位接收新任务处理阻塞队列任务说明RUNNING111YYSHUTDOWN000NY不会接收新任务,但会处理阻塞队列剩余任务STOP001NN会中断正在执行的任务,并抛弃阻塞队列任务TIDYING010--任务全部执行完毕,活动现场为0即进入终结TERMINATED0
2022-03-26 22:37:10
813
原创 7、共享模型之工具 - 1、自定义线程池
1、线程池1、自定义线程池步骤1:自定义拒绝策略@FunctionalInterfacepublic interface RejectPolicy<T> { void reject(BlockingQueue<T> queue, T task);}步骤2:自定义任务队列@Slf4j(topic = "c.BlockingQueue")public class BlockingQueue<T> { // 1.任务队列 priva
2022-03-23 01:44:52
120
原创 6、共享模型之不可变
本章内容不可变类的使用不可变类设计无状态类设计1、日期转换问题问题提出下面代码在运行时,由于SimpleDateFormat 不是线程安全的SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); for (int i = 0; i < 10; i++) { new Thread(() -> { try {
2022-03-13 02:00:53
146
原创 5、共享模式之无锁(下)
7、原子累加器累加器性能比较private static <T> void demo(Supplier<T> adderSupplier, Consumer<T> action) { T adder = adderSupplier.get(); List<Thread> threads = new ArrayList<>(); long start = System.nanoTime();
2022-03-12 16:21:06
357
原创 5、共享模式之无锁(上),CAS,原子类
本章内容CAS 与 volatile原子整数原子引用原子累加器Unsafe6.1、问题的提出有如下需求,保证accont.withdraw取款方法的线程安全public interface Account { // 获取余额 Integer getBalance(); // 取款 void withdraw(Integer amount); /** * 方法内启动1000个线程,那么每个线程做-10的操作 * 如果初始余额
2022-03-10 01:28:02
168
原创 4、Java内存模型、volatile原理、CPU缓存结构、balking模式、单例模式
本章内容上一章讲解的Monitor主要关注的是访问共享变量时,保证临界区代码的原子性这一张进一步深入学习共享变量在多线程之间的【可见性】问题与多条指令执行时的【有序性】问题1、Java内存模型JMM即Java Menory Model,它定义了主存,工作内存的抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等。JMM 体现在以下几个方面原子性 - 保证指令不会受到线程上下文切换的影响可进行 - 保证指令不会受到CPU缓存的影响有序性 - 保证指令不会受到CPU指令优化的影响
2022-03-08 21:58:03
231
原创 3.11、ReentrantLock
相对于synchronized它具备以下特点可中断可以设置超时时间可以设置为公平锁支持多个条件变量与synchronized一样,都支持可重入基本语法reentrantLock.lock();try{ // 临界区} finally { // 释放锁 reentrantLock.unlock();}可重入可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权再次获得这把锁如果是不可冲入锁,那么第二次获得锁时,自己也会被锁挡住 static
2022-03-07 16:35:51
94
原创 3、后记 - 同步模式之顺序控制 (控制线程操作顺序)
1、固定运行顺序比如,必须先2后1打印1.1、wait notify 版本static Object obj = new Object(); static boolean t2runed = false; public static void main(String[] args) { Thread t1 = new Thread(() -> { synchronized (obj) { while(!t2r
2022-03-07 01:22:30
140
原创 第三章小结
写在前面由于本章较长,所以按照小标题发布了本章小结分析多线程访问共享片段时,哪些代码片段属于临界区使用synchronized互斥解决临界区的线程安全问题掌握synchronized锁对象语法掌握synchronized加载成员方法和静态方法语法掌握wait/notify同步方法使用lock互斥解决代码临界区的线程安全问题掌握lock的使用细节:可打断、锁超时、公平锁、条件变量学会分析变量的线程安全性、掌握常见线程安全类的使用了解线程活跃性问题:死锁、活锁、饥饿应用方面
2022-03-07 01:21:51
56
原创 3.10、活跃性、死锁、哲学家就餐、活锁、饥饿
死锁有这样的情况:一个线程需要同时获得多把锁,这时就容易发生死锁t1线程获得A对象锁,接下来想获取B对象的锁,t2线程获得B对象锁,接下来想要获取A对象锁例: Object A = new Object(); Object B = new Object(); new Thread(() -> { synchronized (A) { log.debug("lock A");
2022-03-06 22:06:49
335
原创 3.9、多把锁
多把不相干的锁一间屋子有两个功能:睡觉、学习,互不相干现在小南要学习,小女要睡觉,但如果只用一间屋子(一把锁)的话,那么并发度很低解决方法是准备多个房间(多个对象锁)例如@Slf4j(topic = "c.BigRoom")class BigRoom { public void sleep() { synchronized (this) { log.debug("sleep 2小时"); try {
2022-03-06 18:14:59
104
原创 3.8、重新理解线程转换状态
假设有线程 Thread t情况1 NEW–>RUNNABLE当调用t.start()方法时,由 NEW --> RUNNABLE情况2 RUNNABLE <–> WAITINGt线程用synchronized(obj)获取了对象锁后调用obj.wait() 方法时,t线程从RUNNABLE --> WAITING调用obj.notify(),obj.notifyAll(), t.interrupt()时竞争锁成功,t线程从WAITING --> .
2022-03-06 18:06:06
234
原创 3.7、Park Unpark
基本使用它们是LockSupport类中的方法// 暂停当前线程LockSupport.park();// 回复某个线程的运行LockSupport.unpark(暂停线程对象)先park再unparkpublic static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { log.debug("start...");
2022-03-06 16:23:33
61
原创 3.6、wait notify join原理及应用,同步模式之保护性暂停,异步模式之生产者消费者
小故事 - 为什么要wait由于条件不满足,小南不能继续进行计算但小南如果一直占用着锁,其他人就得一直阻塞,效率太低于是老王单开了一键休息室(调用wait方法),让小南到休息室(WaitSet)等着去了,但这是锁释放开,其他人可以由老王随机安排进屋知道小M将烟送来,大叫一声【你的烟到了】(调用notify方法)小南于是可以离开休息室,重新进入竞争锁的队列原理Owner线程发现条件不满足,调用wait方法,即可进入WaitSet变为WAITING状态BLOCKED和WAITING
2022-03-06 15:58:43
92
原创 3.4、线程安全习题
习题卖票练习测试下面代码是否存在线程安全问题,并尝试改正package sync.test;import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;import java.util.List;import java.util.Random;import java.util.Vector;/** * @author: 言叶长琴 */@Slf4j(topic = "c.ExerciseSell")public cla
2022-03-06 03:07:33
247
原创 3.3、变量的线程安全分析
变量的线程安全分析成员变量和静态变量是否线程安全?如果它们没有共享,则线程安全如果它们被共享了,根据它们的状态是否能够改变,又分两种情况如果只有读操作,则线程安全如果有读写操作,则这段代码是临界区,需要考虑线程安全局部变量是否线程安全局部变量是线程安全的单局部变量引用的对象则未必如果该对象没有逃离方法的作用访问,它是线程安全的如果该对象逃离方法的作用范围,需要考虑线程安全局部变量线程安全分析public static void test1() { int i =
2022-03-06 03:06:14
189
原创 3.2、synchronized关键字 解决竞争的方案
1、synchronized 解决方案为了避免领截取的竞态条件发生,有多种手段可以达到目的。阻塞时的解决方案:synchronized,Lock非阻塞式的解决方案:原子变量本次使用阻塞式的解决方案:synchronized,来解决上述问题,及俗称的【对象锁】,它采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】,其他线程想要获取这个【对象锁】时就会阻塞住。这样就能保证拥有锁的线程可以安全的执行临界区内的代码,不用担心线程的上下文切换注意虽然Java中互斥和同步都可以采用synchro
2022-03-06 03:04:02
500
原创 3、共享模型之管程 -- 3.1、共享带来的问题
1、共享带来的问题小故事老王(操作系统)有一个功能强大的算盘(CPU),现在想把它租出去,赚一点外快小南、小女(线程)来使用这个算盘进行一些计算,并按照时间给老王支付费用但小南不能一天24小事使用算盘,他经常要小憩一会儿(sleep),又或者是去吃饭上厕所(阻塞io操作),有时还需要一根烟,没烟的时候思绪全无(wait),这些情况称为阻塞在这些时候,算盘没有利用起来(不能收钱了),老王觉得有点不划算另外,小女也想用用算盘,如果总是让小南占着算盘,小女觉得不公平于是,老王灵机一动,想了个办
2022-03-06 03:01:27
329
原创 2、Java线程
1、创建和运行线程方法一、直接使用Thread // 直接使用Thread(继承/匿名内部类) Thread t1 = new Thread("t1") { @Override public void run() { log.debug("hello1"); } }; t1.start();方法二、使用Runnable配合Thread // 使用Runnable配合Thread(函数式接口)
2022-03-03 23:05:35
301
原创 1、进程与线程
1 进程与线程1.1 进程与线程进程程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存。在指令运行的过程中还要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理IO的。当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。进程就可以视为程序的一个实例。大部分程序可以同时运行多个实例进程(例如记事本、画图、浏览器等),也有的程序只能启动一个实例进程(例如网易云音乐、360安全卫士等)线程一个进程之内可以分为一到多个线程。
2022-02-27 21:58:56
93
原创 双十一mongo简单检测等
查询正在运行的操作db.currentOp( {"opid":-2048364974});// 中间是查询条件查询结果的一些参数注释 { "inprog" : [ { "opid" : 3434473,//操作的id "active" : <boolean>,//是否处于活动状态
2021-11-01 12:02:21
144
原创 垃圾回收器
GC分类与性能指标垃圾收集器没有在规范中进行过多的规定,可以由不同的厂商、不同版本的JVM来实现。由于JDK的版本处于高速迭代过程中,因此Java发展至今已经衍生了众多的GC版本。从不同角度分析垃圾收集器,可以将GC分为不同的类型。Java不同版本新特性语法层面:Lambda表达式、switch、自动拆箱装箱、enumAPI层面:Stream API、新的日期时间、Optional、String、集合框架底层优化:JVM优化、GC的变化、元空间、静态域、字符串常量池位置变化垃圾收集器
2021-01-22 17:53:03
121
原创 垃圾回收相关概念
System.gc()的理解在默认情况下,通过system.gc()者Runtime.getRuntime().gc() 的调用,会显式触发FullGC,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存。然而system.gc() 调用附带一个免责声明,无法保证对垃圾收集器的调用。(不能确保立即生效)JVM实现者可以通过system.gc() 调用来决定JVM的GC行为。而一般情况下,垃圾回收应该是自动进行的,无须手动触发,否则就太过于麻烦了。在一些特殊情况下,如我们正在编写一个性能基准,我
2021-01-13 16:30:36
107
原创 垃圾回收相关算法
标记阶段:引用计数算法在堆里存放着几乎所有的Java对象实例,在GC执行垃圾回收之前,首先需要区分出内存中哪些是存活对象,哪些是已经死亡的对象。只有被标记为己经死亡的对象,GC才会在执行垃圾回收时,释放掉其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶段。那么在JVM中究竟是如何标记一个死亡对象呢?简单来说,当一个对象已经不再被任何的存活对象继续引用时,就可以宣判为已经死亡。判断对象存活一般有两种方式:引用计数算法和可达性分析算法。引用计数算法(Reference Counting)比较简单,
2021-01-13 13:24:16
144
2
原创 垃圾回收概述
概念这次我们主要关注的是黄色部分,内存的分配与回收什么是垃圾在提到什么是垃圾之前,我们先看下面一张图从上图我们可以很明确的知道,Java 和 C++语言的区别,就在于垃圾收集技术和内存动态分配上,C语言没有垃圾收集技术,需要我们手动的收集。垃圾收集,不是Java语言的伴生产物。早在1960年,第一门开始使用内存动态分配和垃圾收集技术的Lisp语言诞生。 关于垃圾收集有三个经典问题:哪些内存需要回收?什么时候回收?如何回收?垃圾收集机制是Java的招牌能力,极大地提高了开发效率。如今
2021-01-12 15:30:25
113
原创 android sdk配置采坑
环境变量中配置ANDROID_HOME时,路径不能带空格,配完path之后,cmd直接运行adb能跑就疏忽了,没想到还有这回事,说起来,之前nodejs的cache等路径好像也是不能带空格来着,以后这点在弄很多东西之前都要提前预防了...
2021-01-10 01:55:48
141
原创 StringTable
String的基本特性String:字符串,使用一对 ”” 引起来表示String s1 = “mogublog” ; // 字面量的定义方式String s2 = new String(“moxi”);String声明为final的,不可被继承String实现了Serializable接口:表示字符串是支持序列化的。实现了Comparable接口:表示string可以比较大小String在jdk8及以前内部定义了final char[] value用于存储字符串数据。JDK9时改为by
2021-01-07 17:50:32
96
原创 执行引擎
执行引擎概述执行引擎属于JVM的下层,里面包括 解释器、及时编译器、垃圾回收器执行引擎是Java虚拟机核心的组成部分之一。“虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的,而虚拟机的执行引擎则是由软件自行实现的,因此可以不受物理条件制约地定制指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式。JVM的主要任务是负责装载字节码到其内部,但字节码并不能够直接运行在操作系统之上,因为字节码指令并
2021-01-07 16:38:18
131
原创 直接内存 Direct Memory
不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。直接内存是在Java堆外的、直接向系统申请的内存区间。来源于NIO,通过存在堆中的DirectByteBuffer操作Native内存通常,访问直接内存的速度会优于Java堆。即读写性能高。因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存。Java的NIO库允许Java程序使用直接内存,用于数据缓冲区使用下列代码,直接分配本地内存空间int BUFFER = 1024*1024*1024; // 1GBB
2021-01-06 09:55:28
81
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人