目录
- JUC概述
- 1.进程与线程
- 2.并发与并行
- 3.线程的6种状态
- 4.管程
- 5.用户线程和守护线程
- Lock 接口
- 关键字
- 接口
- 和 synchronized 的不同
- 线程间通信
- 线程间定制化通信
- 集合的线程安全
- 线程安全与线程不安全集合
- Collections 构建的线程安全集合
- 并发包下
- 多线程锁
- Callable 接口
- JUC 三大辅助类
- ReentrantReadWriteLock读写锁
- BlockingQueue阻塞队列
- ThreadPool 线程池
- Fork/Join 分支合并框架
- CompletableFuture 异步回调
JUC概述
- JUC就是工具包的简称。
1.进程与线程
进程
指在系统中正在运行的一个应用程序;
程序一旦运行就是进程;
- 1
- 2
进程——资源分配的最小单位。
线程
系统分配处理器时间资源的基本单元,
或者说进程之内独立执行的一个单元执行流。
- 1
- 2
线程——程序执行的最小单位。
2.并发与并行
并发
同一时刻多个线程在访问同一个资源,多个线程对一个点。
例子:春运抢票、电商秒杀
- 1
- 2
并行
多项工作一起执行,之后再汇总
例子:泡方便面,电水壶烧水,一边撕调料倒入桶中
- 1
- 2
3.线程的6种状态
线程状态枚举类
新建:NEW
准备就绪:RUNNABLE
阻塞:BLOCKED
不见不散:WAITING
过时不侯:TIMED_WAITING
终结:TERMINATED
- 1
- 2
- 3
- 4
- 5
- 6
wait/sleep的区别
* sleep是Thread的静态方法, wait是Object的方法,任何对象实例都能调用。
* sleep不会释放锁,它也不需要占用锁。wait会释放锁,但调用它的前提是当前线程占有锁(即代码要在synchronized中)。
* 它们都可以被interrupted方法中断。
- 1
- 2
- 3
4.管程
Monitor监视器
* 操作系统中称为监视器,Java中称为锁
* 一种同步机制,保证同一个时间,只有一个线程访问被保护数据或者代码
* jvm同步基于进入和退出的操作,使用管程对象实现的
- 1
- 2
- 3
5.用户线程和守护线程
用户线程
平时用到的普通线程,自定义线程
- 1
守护线程
运行在后台,是一种特殊的线程,比如垃圾回收
- 1
深入了解 JUC概述 链接
Lock 接口
关键字
synchronized 是 Java 中的关键字,是一种同步锁。
它修饰的对象有以下几种:
1.修饰一个代码块,被修饰的代码块称为同步语句块。
作用的范围:大括号{} 括起来的代码
作用的对象:调用这个代码块的对象
2.修饰一个方法,被修饰的方法称为同步方法。
作用的范围:整个方法
作用的对象:调用这个方法的对象
3.修饰一个静态的方法。
作用的范围:整个静态方法
作用的对象:这个类的所有对象
4.修饰一个类。
作用的范围:synchronized后面括号括起来的部分
作用的对象:这个类的所有对象
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
接口
Lock 锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作。
- ReentrantLock 可重入锁,是唯一实现了 Lock 接口的类
- ReadWriteLock 只定义了两个方法。
- Lock readLock(); //获取读锁
- Lock writeLock(); //获取写锁
- ReentrantReadWriteLock 实现了 ReadWriteLock 接口
- 最主要的有两个方法:readLock()和 writeLock()用来获取读锁和写锁
和 synchronized 的不同
- Lock是一个接口,而synchronized是Java中的关键字,synchronized是内 置的语言实现;
- synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而 Lock 在发生异常时,如果没有主动通过 unLock()去释放锁,则很可能造成死锁现象,因此使用 Lock 时需要在 finally 块中释放锁;
- Lock可以让等待锁的线程响应中断,而synchronized却不行,使用 synchronized 时,等待的线程会一直等待下去,不能够响应中断;
- 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
- Lock可以提高多个线程进行读操作的效率。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时, Lock 的性能要远远优于 synchronized。
深入了解 Lock接口 链接
线程间通信
线程间通信的模型有两种:共享内存和消息传递,
线程间通信案例Demo 链接
线程间定制化通信
A 线程打印 5 次 A,B 线程打印 10 次 B,C 线程打印 15 次 C,按照 此顺序循环 10 轮
线程间定制化通信案例Demo 链接
集合的线程安全
线程安全与线程不安全集合
集合类型中存在线程安全与线程不安全的两种,
常见例如:
ArrayList ----- Vector
HashMap -----HashTable
但是以上都是通过 synchronized 关键字实现,效率较低
Collections 构建的线程安全集合
List: (new ArrayList<>());
Set: (new HashSet<>());
.concurrent 并发包下
CopyOnWriteArrayList、CopyOnWriteArraySet 类型,通过动态数组与线程安全个方面保证线程安全
List: CopyOnWriteArrayList
Set: CopyOnWriteArraySet
Map: ConcurrentHashMap
集合的线程安全 案例Demo 链接
多线程锁
- 普通同步方法:synchronized 锁当前对象 this
- 静态同步方法:static synchronized 锁当前 类
- 同步方法块:synchronized 锁括号里配置的 对象
Callable 接口
JUC 三大辅助类
- CountDownLatch: 减少计数(减 1 操作)
- CyclicBarrier: 循环栅栏(加 1 操作)
- Semaphore: 信号灯(许可证)
JUC三大辅助类案例 链接
ReentrantReadWriteLock读写锁
- 在线程持有读锁的情况下,该线程不能取得写锁
- 在线程持有写锁的情况下,该线程可以继续获取读锁
- demo
//创建读写锁对象
private ReadWriteLock rwLock = new ReentrantReadWriteLock();
//添加写锁
().lock();
//释放写锁
().unlock();
//添加读锁
().lock();
//释放读锁
().unlock();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
ReentrantReadWriteLock读写锁 链接
BlockingQueue阻塞队列
阻塞队列,是一个队列, 通过一个共享的队列,可以使得数据由队列的一端输入,从另外一端输出。
- 当队列是空的,从队列中获取元素的操作将会被阻塞
- 当队列是满的,从队列中添加元素的操作将会被阻塞
阻塞:
在多线程领域:所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦条件满足,被挂起的线程又会自动被唤起
- 常用的队列主要有以下两种:
- 先进先出(FIFO):先插入的队列的元素也最先出队列,类似于排队的功能。从某种程度上来说这种队列也体现了一种公平性
- 后进先出(LIFO):后插入队列的元素最先出队列,这种队列优先处理最近发生的事件(栈)
为什么需要 BlockingQueue?
在 concurrent 包发布以前,在多线程环境下,我们每个程序员都必须去自己控制这些细节,尤其还要兼顾效率和线程安全,而这会给我们的程序带来不小的复杂度。使用后我们不需要关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切 BlockingQueue 都给你一手包办了
BlockingQueue阻塞队列 链接
ThreadPool 线程池
创建线程池推荐用ThreadPoolExecutor及其7个参数手动创建:
- corePoolSize 线程池的核心线程数
- maximumPoolSize 能容纳的最大线程数
- keepAliveTime 空闲线程存活时间
- unit 存活的时间单位
- workQueue 存放提交但未执行任务的队列
- threadFactory 创建线程的工厂类
- handler 等待队列满后的拒绝策略
ThreadPool 线程池 链接
Fork/Join 分支合并框架
Fork 方法的实现原理:
当我们调用 ForkJoinTask 的 fork 方法时,程序会把任务放在 ForkJoinWorkerThread 的 pushTask 的 workQueue 中,异步地执行这个任务,然后立即返回结果
Join 方法:
join 方法的主要作用是阻塞当前线程并等待获取结果。
Fork/Join 框架 链接
CompletableFuture 异步回调
Future 的主要缺点如下:
- 不支持手动完成
- 不支持进一步的非阻塞调用
- 不支持链式调用
- 不支持多个 Future 合并
- 不支持异常处理
CompletableFuture使用:
1 创建一个 CompletableFuture
2 可以创建 没有/有 返回值的异步任务
3 线程依赖
当一个线程依赖另一个线程时,可以使用 thenApply 方法来把这两个线程串行化。
4 消费处理结果
thenAccept 消费处理结果, 接收任务的处理结果,并消费处理,无返回结果。
5 异常处理
exceptionally 异常处理,出现异常时触发
6 结果合并
thenCompose 可以合并两个有依赖关系的 CompletableFutures 的执行结果,也可以合并两个没有依赖关系的 CompletableFutures 任务
合并多个任务的结果 allOf 与 anyOf
• allOf: 一系列独立的 future 任务,等其所有的任务执行完后做一些事情
• anyOf: 只要在多个 future 里面有一个返回,整个任务就可以结束,而不需要等到每一个 future 结束
CompletableFuture 异步回调链接