初识多线程plus(2.0)
2026/6/12 10:46:13 网站建设 项目流程

目录

JUC常⻅类

Callable 接⼝

ReentrantLock

ReentrantLock 和 synchronized 的区别

信号量Semaphore

CountDownLatch

线程安全的集合类

多线程环境使⽤ArrayList

多线程环境使⽤队列

多线程环境使⽤哈希表

2) ConcurrentHashMap


JUC常⻅类

JUC(java.util.concurrent) 的常⻅类

Callable 接⼝

Callable接口 是与Runnable接口 并行关系

相当于把线程封装了⼀个"返回值".⽅便程序借助多线程的⽅式计算结果

Callable<Integer> callable = new Callable<Integer>() { @Override public Integer call() throws Exception { int result = 0; for (int i = 1; i <= 100; i++) { result += i; } return result; } }; FutureTask<Integer> futureTask = new FutureTask<>(callable); Thread t = new Thread(futureTask); t.start(); System.out.println(futureTask.get());

thread 本身不具有获取结果的方法 所以 futureTask 对象获取结果

此外

CallableRunnable相对,都是描述⼀个"任务".Callable描述的是带有返回值的任务,Runnable描述的是不带返回值的任务.

Callable通常需要搭配FutureTask来使⽤.FutureTask⽤来保存Callable的返回结果.因为 Callable 往往是在另⼀个线程中执⾏的,执⾏完并不确定.

FutureTask 就可以负责这个等待结果出来的⼯作.

ReentrantLock

可重⼊互斥锁(与synchronized类似,都是实现互斥效果 并 保证线程安全的

ReentrantLock 有以下三种常见的方法 :

1.lock(): 加锁,如果获取不到锁就死等.

2.trylock(超时时间): 加锁,如果获取不到锁,等待⼀定的时间之后就放弃加锁

3.unlock():解锁

ReentrantLocksynchronized的区别

其一 JVM内外实现的差别synchronized是⼀个关键字是JVM内部实现的

ReentrantLock是标准库的⼀个类,在JVM外实现的

其二 对待阻塞的区别synchronized在申请锁失败时,会死等

但是ReentrantLock会可以使用trylock等待⼀定的时间之后就放弃加锁

其三 锁的类别synchronized是⾮公平锁,

ReentrantLock默认是⾮公平锁.可以通过构造⽅法传⼊⼀个true开启 公平锁模式.

其四synchronized使⽤时不需要⼿动释放锁.

ReentrantLock使⽤时需要⼿动释放.使⽤起来更灵活,但 是也容易遗漏unlock.

其Ⅴ 更强的唤醒机制synchronized是通过 Object 的wait/notify实现等待-唤醒 每次唤醒的是 ⼀ 个随机等待的线程

ReentrantLock搭配Condition类实现等待-唤醒,可以更精确控制唤醒某个 指定的线程.

信号量Semaphore

信号量,⽤来表⽰"可⽤资源的个数". 本质上就是⼀个计数器.

CountDownLatch

同时等待N个任务执⾏结束.

每个任务执⾏完毕 在 CountDownLatch 内部的计数器同时⾃增

线程安全的集合类

多线程环境使⽤ArrayList

1) 自行完成加锁 (synchronized或者ReentrantLock)

分析代码 将其打包成‘原子’再进行加锁

2) Collections.synchronizedList(new ArrayList);

本质作为套壳像是Vector, Stack, HashTable 内含有synchronized

3)使⽤CopyOnWriteArrayList

CopyOnWrite容器(写时复制的容器)

当想在容器内添加新数据时不是选择直接加入而是先copy 一个新的容器在其添加数据

添加完元素之后,再将原容器的引⽤指向新的容器

读多写少的场景下,性能很⾼,不需要加锁竞争反之会非常低效

占⽤内存较多.新写的数据不能被第⼀时间读取到.

也是显然易见的

多线程环境使⽤队列

1)ArrayBlockingQueue

基于数组实现的阻塞队列

2)LinkedBlockingQueue

基于链表实现的阻塞队列

3)PriorityBlockingQueue

基于堆实现的带优先级的阻塞队列

4)TransferQueue

最多只包含⼀个元素的阻塞队列

多线程环境使⽤哈希表

HashMap本⾝不是线程安全的.

但是多线程中使用 哈希表仅此为二

Hashtable

只是简单的把关键⽅法加上了synchronized关键字.

相当于直接针对Hashtable对象本⾝加锁.

所以多线程中 访问同⼀个Hashtable就会直接造成锁冲突

此外size属性也是通过 synchronized 来控制同步,是⽐较慢的

如果⼀旦触发扩容,就由该线程完成整个扩容过程.

这个过程会涉及到⼤量的元素拷⻉,效率会⾮常低

但是 实际上 两个线程恰巧同时访问一个链表的概率是比较低的

ConcurrentHashMap

相⽐于Hashtable做出了⼀系列的改进和优化

1) 简单说 锁对象不在是单个对象

是锁整个对象,⽽是"锁桶"(⽤每个链表的头结点作为锁对象),⼤⼤降低了锁冲突的概率

读操作没有加锁(但是使⽤了volatile保证从内存读取结果),只对写操作进⾏加锁

2)充分利⽤CAS特性

使用原子类对 size类型进行维护

size属性通过CAS来更新.避免出现重量级锁的情况

3)优化了扩容⽅式化整为零

发现需要扩容的线程,只需要创建⼀个新的数组,同时只搬⼏个元素过去.

分次多批的搬运减少耗时

每个来操作ConcurrentHashMap的线程,都会参与搬家的过程.每个操作负责搬运⼀⼩部分元素.

新老数组同时存在 查询时二者一起查询 添加数据仅仅存放到新数组中

当搬完最后⼀个元素再把⽼数组删掉.

over

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询