JUC 重点总结

时间:2025-03-10 07:53:57

目录

  • 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 的不同

  1. Lock是一个接口,而synchronized是Java中的关键字,synchronized是内 置的语言实现;
  2. synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而 Lock 在发生异常时,如果没有主动通过 unLock()去释放锁,则很可能造成死锁现象,因此使用 Lock 时需要在 finally 块中释放锁;
  3. Lock可以让等待锁的线程响应中断,而synchronized却不行,使用 synchronized 时,等待的线程会一直等待下去,不能够响应中断;
  4. 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
  5. 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 异步回调链接