开发基础
JAVA
JUC
多线程
Lock锁
并发容器类
JUC辅助类
JUC底层知识
JVM
本文档使用 MrDoc 发布
-
+
首页
多线程
## wait/sleep的区别 功能都是当前线程暂停,有什么区别? wait:**放开手去睡**,放开手里的锁,就是其他任务可以使用当前线程 sleep:**握紧手去睡**,醒了手里还有锁,当前线程还在使用 wait是Object的方法,sleep是thread的方法 ## 创建线程方式 1. 继承Thread:java是单继承,资源宝贵,要用接口方式 2. 实现Runable接口 3. 实现Callable接口 4. 线程池 #### Callable接口 和 Runnable接口的区别? 相同点: * 都是接口:二者都是 Java 中的接口。 * 编写多线程程序:都可以用于编写多线程程序。 * 启动线程方式:都可以通过 Thread.start() 方法启动线程。 不同点: | 特性 | Runnable | Callable | |------|----------------------------|--------------| | 具体方法 | void run() | <T> T call() | | 返回值 | 无返回值 | 有返回值(泛型类型) | | 异常处理 | 不抛出受检异常(checked exception) | 允许抛出受检异常 | | 功能 | 不提供计算结果检索 | 提供计算结果检索功能 | 说明: * Runnable 的 run() 方法无返回值,且不能抛出受检异常。 * Callable 的 call() 方法可以返回计算结果,并且可以抛出受检异常,通过 Future 接口可以获取计算结果,也能检查或等待计算完成,还能对计算中断做一些特殊处理。 ## ThreadPool线程池 线程池的优势:线程复用;控制最大并发数;管理线程。 1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的销耗。 2. 提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立即执行。 3. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。 ## 架构 Java中的线程池是通过Executor框架实现的,该框架中用到了Executor,ExecutorService,ThreadPoolExecutor这几个类。  ## Executors工具类 | 方法名 | 线程池类型 | 核心线程数 | 最大线程数 | 线程存活时间 | 工作队列 | 适用场景 | 注意事项 | |---------------------------|---------|-------|-------------------|---------|---------------------|-----------------------------|----------------------------------------------| | newCachedThreadPool() | 可缓存线程池 | 0 | Integer.MAX_VALUE | 60秒 | SynchronousQueue | 短时大量异步任务,线程复用高,自动回收空闲线程 | 线程数量可能无限增长,需避免长时间任务导致资源耗尽 | | newFixedThreadPool(n) | 固定大小线程池 | n | n | 0(永久存活) | LinkedBlockingQueue | 已知并发量,需限制线程数量;长期任务或稳定负载场景 | 使用无界队列,任务堆积可能导致内存溢出 | | newSingleThreadExecutor() | 单线程线程池 | 1 | 1 | 0(永久存活) | LinkedBlockingQueue | 需保证任务顺序执行(如文件读写、事件分发等单线程场景) | 同newFixedThreadPool(1),但任务失败后会自动重建线程,仍可能队列堆积 | ## 线程池的7个重要参数 1. corePoolSize:线程池中的常驻核心线程数 2. maximumPoolSize:线程池中能够容纳同时 执行的最大线程数,此值必须大于等于1 3. keepAliveTime:多余的空闲线程的存活时间 当前池中线程数量超过corePoolSize时,当空闲时间达到keepAliveTime时,多余线程会被销毁直到 只剩下corePoolSize个线程为止 4. unit:keepAliveTime的单位 5. workQueue:任务队列,被提交但尚未被执行的任务 6. threadFactory:表示生成线程池中工作线程的线程工厂, 用于创建线程,**一般默认的即可** 7. handler:拒绝策略,表示当队列满了,并且工作线程大于 等于线程池的最大线程数(maximumPoolSize)时,如何来拒绝 请求执行的runnable的策略 ## 线程池底层工作原理  1. 在创建了线程池后,线程池中的**线程数为零**。 2. 当调用execute()方法添加一个请求任务时,线程池会做出如下判断: 1. 如果正在运行的线程数量**小于corePoolSize**,那么马上**创建线程**运行这个任务; 2. 如果正在运行的线程数量**大于或等于corePoolSize**,那么**将这个任务放入队列**; 3. 如果这个时候队列满了且正在运行的线程数量还**小于maximumPoolSize**,那么还是要**创建非核心线程**立刻运行这个任务; 4. 如果队列满了且正在运行的线程数量**大于或等于maximumPoolSize**,那么线程池会**启动饱和拒绝策略**来执行。 3. 当一个线程完成任务时,它会从队列中取下一个任务来执行。 4. 当一个线程无事可做超过一定的时间(keepAliveTime)时,线程会判断: 如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。 所以线程池的所有任务完成后,**它最终会收缩到corePoolSize的大小**。 ## 工作队列 * SynchronousQueue:不存储任务,任务直接交给线程,如果没有线程会立即触发拒绝策略。 * LinkedBlockingQueue:链表结构的阻塞队列,支持无界。 * ArrayBlockingQueue:数组结构的有界阻塞队列。 * PriorityBlockingQueue:带优先级的无界队列。 ## 拒绝策略 一般我们创建线程池时,为防止资源被耗尽,任务队列都会选择创建有界任务队列,但种模式下如果出现**任务队列已满且线程池创建的线程数达到你设置的最大线程数时**,这时就需要你指定ThreadPoolExecutor的RejectedExecutionHandler参数即合理的拒绝策略,来处理线程池"超载"的情况。 ThreadPoolExecutor自带的拒绝策略如下: 1. AbortPolicy(默认):直接**抛出RejectedExecutionException异常**阻止系统正常运行 2. CallerRunsPolicy:“调用者运行”一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是**将某些任务回退到调用者**,从而降低新任务的流量。 3. DiscardOldestPolicy:**抛弃队列中等待最久的任务**,然后把当前任务加人队列中 尝试再次提交当前任务。 4. DiscardPolicy:**该策略默默地丢弃无法处理的任务**,不予任何处理也不抛出异常。 如果允许任务丢失,这是最好的一种策略。 **以上内置的策略均实现了RejectedExecutionHandler接口,也可以自己扩展RejectedExecutionHandler接口,定义自己的拒绝策略** ## 线程通信(Condition) | 方法名称 | 功能描述 | 示例代码 | |------------------------|-------------------|-----------------------------------| | await() | 当前线程等待,直到被通知或中断 | condition.await(); | | awaitUninterruptibly() | 当前线程等待,直到被通知,忽略中断 | condition.awaitUninterruptibly(); | | signal() | 唤醒一个等待的线程 | condition.signal(); | | signalAll() | 唤醒所有等待的线程 | condition.signalAll(); | ``` import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ConditionExample { private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private boolean ready = false; public void producer() { lock.lock(); try { ready = true; condition.signalAll(); // 唤醒所有等待的线程 } finally { lock.unlock(); } } public void consumer() { lock.lock(); try { while (!ready) { condition.await(); // 等待直到条件满足 } // 执行消费操作 } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } ```
admin
2025年3月7日 11:24
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Rancher
Jenkins
ADMIN-UI
VBEN-ADMIN-UI
RUST-FS
MinIO
mindoc
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码