11.线程
AI-摘要
Tianli GPT
AI初始化中...
介绍自己 🙈
生成本文简介 👋
推荐相关文章 📖
前往主页 🏠
前往爱发电购买
11.线程
Pupper一、线程
- 线程是由进程创建的,线程就是进程的实体
- 线程可以分为单线程 和 多线程
- 单线程: 同一时刻,只允许执行一个线程;
- 多线程: 同一时刻,可以执行多个线程; - 并发: 同一时刻,多个任务交替执行,单核 CPU 实现多任务并发; - 并行: 同一时刻,多个任务同时执行,多核 CPU 可以实现并行; - 并行 与 并发 也可能同时存在
1. 线程使用
创建线程的两种方法:
- 继承 Thread 类,重写 run 方法;
- 实现 Runnable 接口,重写 run 方法;
继承 Thread 类,创建线程:
- 主线程结束后,子线程任然在执行时,进程不会结束;
- 调用 run() 方法并不会启动线程,而且会造成主线程阻塞
- 调用 start() 方法可以启动线程,不会造成线程阻塞,主线程和子线程会同时执行
1 | // 继承 Thread 类 - 案例 |
实现 Runnable 接口,创建线程:
- 先创建 Thread 类 : Thread thread = new Thread(实现类);
- 调用 start() 方法,启动线程
1 | // 实现 Runnable 接口 - 案例 |
Thread 和 Runnable 的区别:
- Thread 和 Runnable 在 Java 底层没有区别,都是调用 start();
- 实现 Runnable 接口的方式更加适合多线程共享一个资源的情况,并且可以避免单继承的限制;
2. 线程终止、线程同步
- 当线程完成任务后,会自动退出;
- 通过使用 变量 来控制 run 方法退出的方式来停止线程;
- 使用 synchronized 同步器来修饰买票的方法(防止出现一张票被两人同时抢到)
线程同步(synchronized):
- 在多线程编程中,某些数据不允许被多个线程同时访问,此时就使用线程同步访问技术,保证线程在同一时刻最多只能被一个线程访问,以保证线数据完整性;
- 线程同步: 即 当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作;
- 同步代码块:synchronized(对象){需要被同步的代码};
- synchronized 还可以放在方法声明中,表示整个方法 为 同步方法;
1 | // 售票系统 - 案例 |
3. 线程常用方法
setName | 设置线程名称,使之与参数 name 相同 |
---|---|
getName | 返回线程名称 |
start | 使该线程开始执行, |
run | 调用线程对象 run 方法,run 方法不会创建新线程 |
setPriority | 更改线程优先级,MAX_PRIORITY = 10, MIN_PRIORITY=1,NORM_PRIORITY=5; |
getPriority | 获取线程优先级 |
sleep | 在指定的毫秒数内,线程休眠 |
interrupt | 中断线程, 线程没有关闭,一般用于中断正在休眠的线程 |
1 | // 线程常用方法 - 案例 |
yield | 线程礼让,让出 CPU 让其他线程先执行,因时间不确定,不一定礼让成功 |
join | 线程插队,线程一旦插队成功,则需要先完成插队线程的所有任务 |
1 | // 线程插队 - 案例 |
4.用户线程和守护线程
- 用户线程: 也叫工作线程,当线程的任务执行完 或以 通知的方式结束;
- 守护线程 : 一般是为工作线程服务的,当所有的用户线程结束时,守护线程自动结束。
- 常见的守护线程: 垃圾回收机制
- 设置守护线程: thread.setDaemon(true)
1 | // 守护线程 - 案例 |
5.互斥锁
- 互斥锁: 用来保证共享数据操作的完整性;
- 每个对象都对应一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象;
- 关键字 synchronized 来与对象的互斥锁联系;
- 当某个对象用了 synchronized 修饰时,表示该对象在任一时刻只能由一个线程访问;
- 同步的局限性:导致程序的执行效率要降低;
- 同步方法(非静态的)的锁 可以是 this,也可以是其他对象(要求是同一对象);
- 同步方法(静态的)的锁为当前类本身;
注意事项:
- 同步方法如果没有使用 static 修饰:默认锁对象为 this;
- 如果方法使用 static 修饰,默认锁对象为 当前类.class
- 实现步骤:
- 分析需要上锁的代码;
- 选择同步代码块或同步方法;
- 要求多个线程的锁对象为同一个;
1 | // 互斥锁 - 案例 |
6.死锁
线程死锁:
- 多个线程都占用了对象的锁资源,但不肯相让,导致了死锁,在编程里一定要避免死锁的发生;
- 多个线程互相获取了对方想要获取的线程锁,即为死锁
7. 释放锁
释放锁的情形:
- 当前线程的同步方法,同步代码块执行结束;
- 当前线程在同步代码块、同步方法中遇到了 break、return;
- 当前线程在同步代码块、同步方法中出现了未处理的 Error 或 Exception,导致异常结束;
- 当前线程在同步代码快、同步方法中执行了线程对象的 wait() 方法,当前线程暂停,并释放锁;
不会释放锁的情形:
- 线程执行同步代码块或同步方法时,程序调用 Thread.sleep()、Thread.yield() 方法暂停当前线程执行,不会释放锁;
- 线程执行同步代码块时,其他线程调用类该线程的 suspend() 方法,将该线程挂起,该线程不会释放锁;
案例
1 | // 输入字母 Q ,暂停随机数 |
1 | // 两个线程分别取钱 |
评论
匿名评论隐私政策
✅ 你无需删除空行,直接评论以获取最佳展示效果