day21
day21
线程
Thread提供的常用方法 | 说明 |
---|---|
public void run() | 线程的任务方法 |
public void start() | 启动线程 |
public String getName() | 获取当前线程的名称,线程名称默认是Thread-索引 |
public void setName(String name) | 为线程设置名称 |
public static Thread currentThread() | 获取当前执行的线程对象 |
public static void sleep(long time) | 让当前执行的线程休眠多少毫秒后,再继续执行 |
public final void join()... | 让调用当前这个方法的线程先执行完! |
Thread提供的常见构造器 | 说明 |
---|---|
public Thread(String name) | 可以为当前线程指定名称 |
public Thread(Runnable target) | 封装Runnable对象成为线程对象 |
public Thread(Runnable target, String name) | 封装Runnable对象成为线程对象,并指定线程名称 |
线程安全问题
- 多个线程,同时操作同一个共享资源的时候可能出现线程安全问题
解决线程安全问题:线程同步
线程同步
- 解决线程安全问题的方案
线程同步的思想
- 让多个线程实现先后依次访问资源
线程同步的常见方案
- 加锁:每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程才能再加锁进来
线程同步的方式
- 同步代码块
- 同步方法
- Lock锁
同步代码块
-
作用:把访问共享资源的核心代码给上锁,以此保证线程安全。
-
原理:每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行。
同步锁的注意事项
- 对于当前同时执行的线程来说,同步锁必须是同一把(同一个对象),否则会出bug
锁对象使用规范
- 建议使用共享资源作为锁对象,对于实例方法建议使用this作为锁对象。
- 对于静态方法建议使用字节码(类名.class)对象作为锁对象。
同步方法
-
作用:把访问共享资源的核心方法给上锁,以此保证线程安全。
-
原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。
原理
-
同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码。
-
如果方法是实例方法:同步方法默认用this作为的锁对象。
-
如果方法是静态方法:同步方法默认用类名.class作为的锁对象。
同步代码块和同步方法的区别
范围上:同步代码块锁的范围更小,同步方法锁的范围更大。
可读性:同步方法更好。
Lock锁
-
Lock锁是JDK5开始提供的一个新的锁定操作,通过它可以创建出锁对象进行加锁和解锁,更灵活、更方便、更强大。
-
Lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象。
构造器 | 说明 |
---|---|
public ReentrantLock() | 获得Lock锁的实现类对象 |
方法名称 | 说明 |
---|---|
void lock() | 获得锁 |
void unlock() | 释放锁 |
线程通信
- 当多个线程共同操作共享的资源时,线程间通过某种方式互相告知自己的状态,以相互协调,并避免无效的资源争夺。
生产者消费者模型
-
生产者线程负责生产数据
-
消费者线程负责消费生产者生产的数据。
-
注意:生产者生产完数据应该等待自己,通知消费者消费;消费者消费完数据也应该等待自己,再通知生产者生产!
Object类的等待和唤醒方法:
方法名称 | 说明 |
---|---|
void wait() | 让当前线程等待并释放所占锁,直到另一个线程调用notify()方法或 notifyAll()方法 |
void notify() | 唤醒正在等待的单个线程 |
void notifyAll() | 唤醒正在等待的所有线程 |
线程的生命周期
- 也就是线程从生到死的过程中,经历的各种状态及状态转换。
- 理解线程这些状态有利于提升并发编程的理解能力。
Java线程的状态
- Java总共定义了6种状态
- 6种状态都定义在Thread类的内部枚举类中
Java有如下六种状态
- New新建
- Runnable可运行
- Blocked阻塞
- waitting无限等待
- Timed_waitting计时等待
- terminated终止
线程状态 | 说明 |
---|---|
NEW(新建) | 线程刚被创建,但是并未启动。 |
Runnable(可运行) | 线程已经调用了start(),等待CPU调度 |
Blocked(锁阻塞) | 线程在执行的时候未竞争到锁对象,则该线程进入Blocked状态。 |
Waiting(无限等待) | 一个线程进入Waiting状态,另一个线程调用notify或者notifyAll方法才能够唤醒 |
Timed Waiting(计时等待) | 同waiting状态,有几个方法(sleep,wait)有超时参数,调用他们将进入Timed Waiting状态。 |
Teminated(被终止) | 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。 |
线程池
线程池就是一个可以复用线程的技术
线程池是一个容器,可以保存一些线程对象,这些线程可以反复使用
为什么用线程池
用户每发起一个请求,后台就需要创建一个新线程来处理,下次新任务来了肯定又要创建新线程处理的, 而创建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,这样会严重影响系统的性能。
优势
- 降低资源消耗,重复利用线程池中线程,不需要每次都创建和销毁
- 便于线程管理,线程池可以集中管理线程
Executors
- 是一个线程池的工具类,提供了很多静态方法用于返回不同特点的线程池对象。
方法名称 | 说明 |
---|---|
public static ExecutorService newFixedThreadPool(int nThreads) | 创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。 |
public static ExecutorService newSingleThreadExecutor() | 创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程。 |
public static ExecutorService newCachedThreadPool() | 线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了60s则会被回收掉。 |
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) | 创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务。 |
注意 :这些方法的底层,都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象。
Executors使用可能存在的陷阱:
大型并发系统环境中使用Executors如果不注意可能会出现系统风险。
创建线程池
线程池的使用方式1-提交Runnable任务
Executors工具类创建线程池
JDK 1.5起提供了线程池,Executors类是线程池的工具类,通过Executors工具类可以创建线程池。
方法名 | 说明 |
---|---|
static ExecutorService newFixedThreadPool(int nThreads) | 创建一个线程池,该线程池固定数量的线程 |
ExecutorService:真正的代表线程池的接口。常见实现类ThreadPoolExecutor
ExecutorService线程池中的常用方法
方法名 | 说明 |
---|---|
submit(Runnable task) | 提交Runnable类型的任务 |
submit(Callable |
提交Callable类型的任务 |
void shutdown() | 关闭线程池 |
线程池的使用方式2-提交Callable任务
Callable方式好处
- 有返回值
- 可以抛异常
- 线程池的使用步骤
- 创建线程池
- 创建Callable任务
- 提交任务
线程池的执行原理
线程池的使用方式3-ThreadPoolExecutor手动创建线程池
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,RejectedExecutionHandler handler)
参数一 corePoolSize:指定线程池的线程数量(核心线程)
参数二 maximumPoolSize:指定线程池可支持的最大线程数
参数三 keepAliveTime:指定临时线程的最大存活时间
参数四 unit:指定线程存活时间的单位(秒、分、时、天)
参数五 workQueue:指定任务存放的队列
参数六 threadFactory:指定用谁来创建线程
参数七 handler:任务满的时候如何处理(拒绝策略)
拒绝策略 | 详解 |
---|---|
ThreadPoolExecutor.AbortPolicy | 丢弃任务并抛出RejectedExecutionException异常。是默认的策略 |
ThreadPoolExecutor.DiscardPolicy | 丢弃任务,但是不抛出异常 这是不推荐的做法 |
ThreadPoolExecutor.DiscardOldestPolicy | 抛弃队列中等待最久的任务 然后把当前任务加入队列中 |
ThreadPoolExecutor.CallerRunsPolicy | 由主线程负责调用任务的run()方法从而绕过线程池直接执行 |
本文来自博客园,作者:萌新小夏,转载请注明原文链接:https://www.cnblogs.com/xkh-blogs/p/17250330.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具