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对象成为线程对象,并指定线程名称

线程安全问题

  • 多个线程,同时操作同一个共享资源的时候可能出现线程安全问题

解决线程安全问题:线程同步

线程同步

  • 解决线程安全问题的方案

线程同步的思想

  • 让多个线程实现先后依次访问资源

线程同步的常见方案

  • 加锁:每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程才能再加锁进来

线程同步的方式

  1. 同步代码块
  2. 同步方法
  3. 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有如下六种状态

  1. New新建
  2. Runnable可运行
  3. Blocked阻塞
  4. waitting无限等待
  5. Timed_waitting计时等待
  6. 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 task) 提交Callable类型的任务
void shutdown() 关闭线程池

线程池的使用方式2-提交Callable任务

Callable方式好处

  • 有返回值
  • 可以抛异常
  1. 线程池的使用步骤
  2. 创建线程池
  3. 创建Callable任务
  4. 提交任务

线程池的执行原理

线程池的使用方式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()方法从而绕过线程池直接执行
posted @   萌新小夏  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示