目录
学习的知识体系图片太大,直接奉上链接,可以自己保存到电脑上:https://blog.csdn.net/qq_43040688/article/details/105819866
这些全部都是博主学习时记录的一些笔记,手上也有学习时使用的相关的网课资源或者是课本资源,感觉讲的都很不错,资料也很全。
可以在文章底下评论,我会私信联系你,如果觉得资源不错,可以为这篇文章点个赞
,让更多的人可以看到~~
一. 数据库
1.1 关系型数据库
MySQL(已更新)
推荐书目:《MySQL必知必会》、《MySQL技术内幕》、《高性能MySQL》
对于MySQL语法优先学习SQL的语句增删改查等,然后在LeetCode练习一下数据库的题目,可能会手写SQL语句
接着需要重点学习索引、锁、事务、SQL优化以及MySQL的架构
1.2 非关系型数据库
Redis
二、Java基础
2.1 Java虚拟机(已更新)
虛拟机推荐 《深入理解Java虚拟机》 这本书,重点学习一下内存
、垃圾回收
、类加载机制
这几部分内容。
2.2 Java并发(已更新)
Java并发主要看了汪文君的并发三个阶段,内容比较丰富,看了很久
Java并发基础
学习Java并发,需要先掌握线程的一些基础知识
这些基础知识的组合构成了后面的设计模式
- 首先应该了解如何启动一个多线程,即使用Runnable、Callable、Thread;还需要了解线程启动后的生命周期,了解了不用实现方式的差别,最重要的研读Thread的源码,详情参考:
Java多线程起步
,Thread构造函数源码分析
- 需要学习Thread常用API以及三种关闭线程的方式,详情参考:
Thread的API
- 需要了解this锁和class锁,详情参考:
Java多线程之认识“锁”
- 需要了解线程间的通讯,最基本的就是消费者和生产者模型,需要深入了解了wait、sleep、notify、nitifyAll的机制和差异,对于wait set要有个清晰的认识,详情参考:
Java多线程之线程间的通讯
- 需要尝试自定义了一个Boolean锁,了解了加锁和释放锁的过程,实现了获取正在阻塞的线程;需要了解线程运行时出现异常的处理方式
,详情参考:自定义Boolean锁&捕获线程中的异常
- 需要学习了线程组的概念以及常用API,如interrupt,setDaemon,activeCount,enumerate, 详情参考:
线程组
- 需要自定义了一个线程池,对线程池的处理机制有了较深的理解,详情参考:
自定义线程池
多线程的设计模式
Java在并发的场景中,设计模式就像个套路,开发者可以自由的组合以满足应用需求
下面有十四个多线程的设计模式,帮助理解后面的JUC包。
-
第一个设计模式是:观察者模式。需要定义一个主题,一个观察者。主题在多线程情况下,可以实现Runnable接口,传递给线程;线程在执行的过程中,可能会修改主题的状态;主题状态发生变化,会通知观察者,执行观察者的onChange方法。详情参考:
观察者模式
-
第二个设计模式是:单例模式。解决方式有三种:第一种是double check方式,但是可能会引起空指针异常;第二种是holder方式,利用内部static 类实现;第三种是利用enum类实现。详情参考:
单例模式
-
第三个设计模式是单线程执行模式。就是在同一时刻只能有一个对共享资源进行操作。详情参考:
单线程执行设计模式
-
第四个设计模式不可变对象设计模式。是一种无锁的设计模式,其思想是如果共享资源是不可以修改的,则线程一定安全。详情参考:
不可变对象设计模式
-
第五个设计模式确保挂起设计模式。当线程在工作时,如果来了其他任务,将任务放入到队列中等待。详情参考:
确保挂起设计模式
-
第六个设计模式Balking设计模式。当工作已经执行过了,就直接return,防止重复的工作,提高效率。详情参考:
Balking设计模式
-
第七个设计模式生产者-消费者设计模式。如果生产一个产品,放到吧台上,通知消费者;如果吧台上有产品,消费者就会立即执行。详情参考:
生产者-消费者设计模式
-
第七个设计模式读写锁的设计模式。读取操作与读取操作之间不存在线程安全的问题,所以在此情况下,避免加锁,影响性能。详情参考:
读写锁的设计模式
-
第八个设计模式Thread-Per-Message。每一个请求都创建一个线程服务,为了提高性能,可以使用线程池。详情参考:
Thread-Per-Message
-
第九个设计模式 Worker 设计模式。需要一个Master,负责创建worker、启动worker、监控worker以及接受任务。
详情参考:Worker 设计模式
-
第十个设计模式Future设计模式。通过返回一个票据,避免陷入阻塞;当任务完成后,可以调用票据的get方法获取结果。详情参考:
Future设计模式
-
第十一个设计模式两阶段终止设计模式。当线程关闭时,不会立马关闭,而是先执行第二阶段的资源释放任务。利用的try…finally…。详情参考:
两阶段终止设计模式
-
第十二个设计模式线程保险箱设计模式。利用Map,线程是key,数据是value。可以保证线程间的数据是安全的。需要注意:线程池下,需要清空原来的数据。详情参考:
线程保险箱设计模式
和上下文设计模式
-
第十三个设计模式Active Objects 设计模式。接受异步调用的主动方法。可以主动异步的执行一些任务。详情参考:
Active Objects 设计模式
-
第十四个设计模式Count Down设计模式。多个子任务执行,主任务等待子任务全部执行完,再执行详情参考:
Count Down设计模式
Java高并发与JVM的关系
主要是学习
wait set
、JMM模型
JMM模型中有四个内容,主要参看博客:Java多线程之内存模型三大特性
。如果想学习更多,请学习JVM的部分。
- 解决高速缓存中数据不一致性的问题——总线锁(效率低)、高速缓存一致性协议,英特尔
- 高并发的三个要求——原子性、可见性、有序性
- happens-before
- 指令重排序
Java多线程之内存模型三大特性:https://blog.csdn.net/qq_43040688/article/details/105823532
原子包
CAS :
- 乐观锁,CompareAndSwap。
- 优点是:保证变量的原子性;避免从用户态到内核态,可以提高性能确定。
- 缺点:在竞争激烈的情况下,浪费CUP资源。
- 还有一个问题是ABA问题,解决方法是:加一个版本号。
- 详情参考:
CAS
UnSafe类
- 内部有很多native方法,是执行的是C++的代码,给了Java操作内存的方式
- 获取Unsafe需要通过
反射
Unsafe类的属性 - 常用的功能:CAS、加载类(可以不运行构造方法)、能直接操作内存、内置锁的实现
- 详情参考:
UnSafe类
AtomicInteger和AtomicBoolean:
- 是保证原子性的对象。
- 利用的CAS
- 详情参考:
AtomicInteger
和AtomicBoolean
AtomicReference
- 是一个利用CAS帮助对象保证原子性的
- 但是存在ABA问题,解决该问题的是:AtomicStampedReference,详情参考:
CAS
- 详情参考:
AtomicReference
JUC工具包
CountDownLatch
- 通过一个计数器实现,计数器初始值就是线程的数量
- 每当一个线程完成任务,就会使计数减一
- 可以在多线程环境使用,使多个线程阻塞,等待上一阶段任务的全部完成
- 详情见:
CountDownLatch
CyclicBarrier
- 跟
CountDownLatch
的区别是:完成任务后需要等待其他线程完成任务,同时是一个可重用点 - 详情见:
CyclicBarrier
Phaser
- JDK1.7之后引用的,具有
CyclicBarrier
和CountDownLatch
- 同时它的注册数是支持动态增加或减少(可以用于线程出现异常)
- 当它在一个阶段所有任务完成时,会进入下一阶段,同时计数器重新恢复
- 详情见:
Phaser
Exchanger
- 用于线程间交换数据
- 需要注意一点:交换的数据对象是一个引用,而不是拷贝,需要考虑线程安全问题
- 详情见:
Exchanger
Semaphore
- 是一个对共享资源管理的设施,通过对信号量的控制,可以让资源被多个线程访问
- 详情见:
Semaphore
ReentrantLock
- 支持公平锁,即尽可能的保证线程之间获取时间片的次数的相同的
- 支持tryLock机制,尝试获取锁,如果没有获取到,不会阻塞
- 需要手动的释放锁,try…finally…
- 相较内置锁而言,是基于AQS实现的,不需要一个从用户态到内核态的过程,性能更高
- 是一个Java类,具有更多的功能,同时可以自由的扩展
- 详情请见:
ReentrantLock
读写锁
- 将读和写分为两个锁,可以有效解决读-读之间的冲突问题,大幅提高性能
- 是悲观锁,可能读的线程太多,写的线程迟迟难以执行
- 详情请见:
读写锁
StampedLock
- 解决读写锁中,写的线程迟迟难以执行的过程,是一个乐观锁
- 思路是:获得一个乐观的读锁,先读取数据;在返回数据时,检测数据是否有被写入,如果有,则获取一个悲观读锁,重新读取数据
- 详情请见:
StampedLock
三种锁的比较
synchronized | StampedLock | Lock |
---|---|---|
是JVM的的内置锁,每个JDK版本都会优化 | 是一个Java类,可以更好的扩展 | 是一个Java类,可以更好的扩展 |
都是悲观锁 | 提供了写的乐观锁 | 都是悲观锁,但是提供了自旋锁,或者不阻塞的获取锁 |
性能一般,因为有一个从用户态到内核态的过程 | 性能最好,可以代替读写锁 | 性能十分不稳定,在复杂的读写环境下,性能十分差 |
- 详情请见:
三种锁的比较
ForkJoin
- 基本思想是:如果当前线程执行任务速度比较慢,则将此任务拆分,交给子线程执行
- 分为Fork和Join两个阶段,充分利用CPU资源
- 详情请见:
ForkJoin
Exectors框架
首先需要学习线程池的构造方法中参数的意义,如果可以尽量不要使用工厂方法创建线程池。
ThreadPoolExecutor
- 创建线程池有七大参数,
特别重要
- 有四种拒绝策略
- 四种阻塞队列
- 一些调试的API
- 关闭线程池的注意事项
- 详情请见:
ThreadPoolExecutor
Executors
用来创建线程池,可以创建5种线程池,需要对这些线程池特性很熟悉:
- newCachedThreadPool
- newFixedThreadPool
- newScheduledThreadPool
- newSingleThreadExecutor
- newWorkStealingPool
- 详情请见:
Executors
CompletionService
- 用来增强线程池,主要思想是:
执行一批任务,先执行的,先获取结果
- 实现的子类是:
ExecutorCompletionService
- 详情请见:
CompletionService
CompleableFuture
- 可以进行串联的操作,即利用上一个任务的结果,执行下一个任务
- 进行并联的操作,即多个线程执行不同任务,最先执行完成的任务结果将作为这一批任务的结果
- 可以不需要调用者主动获取结果,而进行回调
- 执行一批任务时,获取的Future是按照任务完成的顺序
- 创建CompleableFuture有多种方式,最多的是
runAsync
和supplyAsync
- API分为组合方法、中转方法和终结方法
- 详情请见:
CompleableFuture
文章名称 | 链接 |
---|---|
ThreadPoolExecutor | https://blog.csdn.net/qq_43040688/article/details/106041236 |
Executors | https://blog.csdn.net/qq_43040688/article/details/106046629 |
CompletionService | https://blog.csdn.net/qq_43040688/article/details/106058225 |
CompleableFuture | https://blog.csdn.net/qq_43040688/article/details/106061776 |