Java 多线程

123 阅读4分钟

一、多线程的实现方式

  1. 继承Thread类的方式进行实现
  2. 实现Runnable接口的方式进行实现
  3. 利用Callable接口和Future接口方式实现
优点缺点
继承Thread类编程简单,可以直接使用Thread类中的方法可以扩展性较差,不能再继承其他的类
实现Runnable接口扩展性强,实现该接口的同时还可以继承其他的类编程较为复杂,不能直接使用Thread类中的方法
实现Callable接口同上同上

截屏2023-07-04 21.56.54.png

截屏2023-07-04 21.54.55.png

截屏2023-07-05 20.29.29.png

二、常见的成员方法

方法名称说明
String getName()返回此线程的名称
void setName(String name)设置线程的名字(构造方法也可以设置名字)
static Thread currentThread()获取当前线程的对象
static void sleep(long time)让线程休眠指定的时间,单位为毫秒
setPriority(int newPriority)设置线程的优先权
final int getPriority()获取线程的优先级
final void setDaemon(boolean on)设置为守护线程
public static coid yield()出让线程 / 礼让线程
public static void join()插入线程 / 插队线程
  • 基本操作 截屏2023-07-05 21.05.15.png

  • 守护线程 截屏2023-07-07 21.40.07.png

  • 出让线程 截屏2023-07-08 11.11.14.png

  • 插入线程 截屏2023-07-08 10.52.21.png

三、线程的安全问题

  • 需求:某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票
  • 安全问题:相同的票出现了多次、出现超出范围的票
  • 原因:线程执行时,有随机性。
  • 解决方法:同步代码块、同步方法、Lock锁

截屏2023-07-08 16.09.39.png

1. 同步代码块

把操作共享数据的代码锁起来。
synchronized(锁) {操作共享数据的代码}
特点:

  • 锁默认打开,有一个线程进去了,锁自动关闭
  • 里面的代码全部执行完毕,线程出来,锁自动打开

截屏2023-07-08 16.27.03.png

2. 同步方法

就是把synchronized关键字加到方法上
修饰符 synchronized 返回值类型 方法名(方法参数){...} 特点:

  • 同步方法是锁住方法里面的所有的代码
  • 锁对象不能自己指定:非静态(this)、静态:当前类的字节码文件对象

截屏2023-07-10 14.56.42.png

3. Lock锁

  • 虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更加清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock
  • Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作,Lock中提供了获得锁和释放锁的方法。
    void lock(): 获得锁
    void unlock(): 释放锁
  • Lock是接口不能直接实例化,这里采用他的实现类ReentrantLock来实例化ReentrantLock的构造方法。
    ReentrantLock(): 创建一个ReentrantLock的实例

截屏2023-07-10 15.43.35.png

四、死锁

1. 死锁产生的原因

  • 互斥、不可剥夺、请求保持、循环等待。
  • 常见的死锁产生的原因:锁嵌套。

截屏2023-07-06 10.35.07.png

2. 生产者消费者

截屏2023-07-06 10.39.23.png

方法名称说明
void wait()当前线程等待,直到被其他线程唤醒
void notify()随机唤醒单个线程
void notifyAll()唤醒所有线程

截屏2023-07-06 11.16.40.png

截屏2023-07-06 11.18.24.png

截屏2023-07-06 11.18.32.png

截屏2023-07-06 11.19.26.png

3. 等待唤醒机制(阻塞队列方式实现)

截屏2023-07-06 11.22.44.png

截屏2023-07-06 11.23.47.png

截屏2023-07-06 11.32.29.png

截屏2023-07-06 11.35.01.png

4.线程的状态

截屏2023-07-06 11.35.34.png 截屏2023-07-06 11.36.46.png

五、线程池

  1. 创建一个池子,池子中是空的
  2. 提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子。下回再次提交任务时,不需要创建新的线程,直接复用已有的线程
  3. 但是如果提交任务时,池子中没有空闲的线程,也无法创建新的线程,任务就会排队等待。

1. 线程池的代码实现

Excutors:线程池的工具类通过调用方法返回不同类型的线程池对象。

方法名称说明
public static ExecutorService newCachedThreadPool()创建一个没有上限的线程池
public static ExecutorService newFixedThreadPool(int nThreads)创建有上限的线程池

2. 以前写多线程的弊端

  • 用到线程的时候就创建
  • 用完之后线程消失

截屏2023-07-07 15.51.23.png

截屏2023-07-07 15.51.34.png

(21条消息) Java面试题总结 - Java多线程篇(附答案)_多线程面试题_哪 吒的博客-CSDN博客