Files
Java-Basic-and-Advanced/线程.md
2026-01-07 16:14:38 +08:00

467 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 线程
## 进程和线程
### 进程介绍:
![image-20251226164954480](https://gitee.com/icecat2233/picture/raw/master/20251226164956071.png)
<img src="https://gitee.com/icecat2233/picture/raw/master/20251226170135578.png" alt="image-20251226170130636" style="zoom:50%;" />
### 线程Thread介绍
进程可以同时执行多个任务,每个任务就是线程:
### 多线程的作用:
提升执行效率,使更多进程可以并行执行
服务器必须用多线程
## Java中开启线程的方式
### 1:继承Thread类
案例:
```Java
public static void main(String[] args) {
/*
* 继承Thread类
* 重写run方法
* 将线程任务代码写在run方法
* 创建对象
* 对象名.start开启线程
* 只有调用start方法才会开启一个新线程
*/
Demo d1 = new Demo();
Demo d2 = new Demo();
d1.start();
d2.start();
}
}
class Demo extends Thread {
@Override
public void run() {
for (int i = 1; i <= 200; i++) {
System.out.println("打印了" + i);
}
}
}
```
### 注意:
![image-20251226175706557](https://gitee.com/icecat2233/picture/raw/master/20251226175707664.png)
### 2实现Runnable接口
```java
/*
方法2 实现runnable接口
编写一个类实现接口
重写run方法
创建线程任务资源(就是创建对象)
然后创建线程对象,将任务资源传入,走构造方法
使用线程对象调用start方法
*/
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread tr = new Thread(mr);
tr.start();
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("八奈见杏菜");
}
}
```
### 3实现Callable接口(有结果返回)
```java
public class ThreadDemo3 {
public static void main(String[] args) throws Exception {
/*
创建一个类实现Callable接口
重写call方法
创建线程任务资源对象
创建线程任务对象封装线程任务资源FutureTask
创建线程对象传入线程任务
使用线程对象调用start方法开启线程
*/
MyCallAble mc = new MyCallAble();
FutureTask<Integer> ft = new FutureTask<>(mc);
Thread t = new Thread(ft);
t.start();
Integer result = ft.get();
System.out.println(result);
}
}
class MyCallAble implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
return sum;
}
}
```
### 尽量选择后两个,拓展性更好
## 线程的方法
![image-20251226195404148](https://gitee.com/icecat2233/picture/raw/master/20251226195406047.png)
### 名字相关:
![image-20251226195311173](https://gitee.com/icecat2233/picture/raw/master/20251226195312281.png)
### 休眠线程:
<img src="https://gitee.com/icecat2233/picture/raw/master/20251226195658228.png" alt="image-20251226195657226" style="zoom: 67%;" />
### 线程调度方法:
Java是抢占式调度
<img src="https://gitee.com/icecat2233/picture/raw/master/20251226200312037.png" alt="image-20251226200310813" style="zoom:67%;" />
### 守护线程
`final void setDaemon(boolean on );`
<img src="https://gitee.com/icecat2233/picture/raw/master/20251226200638217.png" alt="image-20251226200636908" style="zoom: 67%;" />
如图代码所示t2守护t1t1线程任务结束t2也结束(不是立刻结束t2会在苟活一会儿)
哪个线程对象调用setDaemon方法这个线程就是守护线程
## 线程的安全与同步
<img src="https://gitee.com/icecat2233/picture/raw/master/20251227180107783.png" alt="image-20251227180059497" style="zoom: 50%;" />
### 1.同步代码块:
![image-20251227181232243](https://gitee.com/icecat2233/picture/raw/master/20251227181233315.png)
**使用同步代码块指定锁对象时,用类的字节码对象**
**共享数据要用static修饰**
### 2.同步方法:
<img src="https://gitee.com/icecat2233/picture/raw/master/20251227182958488.png" alt="image-20251227182957021" style="zoom: 67%;" />
### 3.Lock锁
```Java
public static void main(String[] args) {
TicketShop1 ts = new TicketShop1();
Thread t1 = new Thread(ts);
Thread t2 = new Thread(ts);
Thread t3 = new Thread(ts);
t1.start();
t2.start();
t3.start();
}
}
class TicketShop1 implements Runnable{
private int ticket = 100;
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
//上锁
try {
lock.lock();
if (ticket == 0){
break;
}
System.out.println("卖出了"+ticket+"号票");
ticket--;
} finally {
//记得关闭锁
lock.unlock();
}
}
}
}
```
附加知识点:死锁:
<img src="https://gitee.com/icecat2233/picture/raw/master/20251227184708459.png" alt="image-20251227184706346" style="zoom:50%;" />
## 线程通信
<img src="https://gitee.com/icecat2233/picture/raw/master/20251228190237885.png" alt="image-20251228190234137" style="zoom:50%;" />
### 两条线程交替执行案例:
```Java
public static void main(String[] args) {
Print p = new Print();
Thread t1= new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (Print.class) {
try {
p.print1();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (Print.class) {
try {
p.print2();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
});
t2.start();
}
}
class Print{
private int flag = 1;
public void print1() throws InterruptedException {
if (flag != 1){
//wait只能通过锁对象进行调用
Print.class.wait();
}
System.out.print("");
System.out.print("");
System.out.print("");
System.out.print("");
System.out.print("");
System.out.println();
flag = 2;
//notif拥有空唤醒的权利
Print.class.notify();
}
public void print2() throws InterruptedException {
if (flag != 2){
Print.class.wait();
}
System.out.print("");
System.out.print("");
System.out.print("");
System.out.print("");
System.out.println();
flag = 1;
Print.class.notify();
}
}
```
### 注意事项:
<img src="https://gitee.com/icecat2233/picture/raw/master/20251228190306178.png" alt="image-20251228190304630" style="zoom: 67%;" />
### 若想提升效率使用ReentrantLock实现同步获取Condition对象
<img src="https://gitee.com/icecat2233/picture/raw/master/20251228191731287.png" alt="image-20251228191729896" style="zoom:50%;" />
注意:第一次指定线程等待时,绑定了线程
### 三条线程交替执行案例:
```Java
public static void main(String[] args) {
Printer p = new Printer();
Thread t1= new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
p.print1();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
p.print2();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
t2.start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
p.print3();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}).start();
}
}
class Printer{
private int flag = 1;
ReentrantLock lock = new ReentrantLock();
//调用newCondition来获取条件对象以此来指定线程
Condition c1 = lock.newCondition();
Condition c2 = lock.newCondition();
Condition c3 = lock.newCondition();
public void print1() throws InterruptedException {
lock.lock();
if (flag != 1){
//第一次调用await方法时绑定了线程
c1.await();
}
System.out.print("");
System.out.print("");
System.out.print("");
System.out.print("");
System.out.print("");
System.out.println();
flag = 2;
c2.signal();
lock.unlock();
}
public void print2() throws InterruptedException {
lock.lock();
if (flag != 2){
c2.await();
}
System.out.print("");
System.out.print("");
System.out.print("");
System.out.print("");
System.out.println();
flag = 3;
c3.signal();
lock.unlock();
}
public void print3() throws InterruptedException {
lock.lock();
if (flag != 3){
c3.await();
}
System.out.print("");
System.out.print("");
System.out.print("");
System.out.print("");
System.out.println();
flag = 1;
c1.signal();
lock.unlock();
}
}
```
### 生产者消费者模式:
<img src="https://gitee.com/icecat2233/picture/raw/master/20251228193331390.png" alt="image-20251228193330122" style="zoom:50%;" />
<img src="https://gitee.com/icecat2233/picture/raw/master/20251228193430647.png" alt="image-20251228193429569" style="zoom:50%;" />
### 生产者消费者案例:
<img src="https://gitee.com/icecat2233/picture/raw/master/20251228193309975.png" alt="image-20251228193308023" style="zoom:67%;" />
## 线程生命周期:
<img src="https://gitee.com/icecat2233/picture/raw/master/20251228194047345.png" alt="image-20251228194046082" style="zoom:67%;" />
## 线程池:
重点:自定义线程池
<img src="https://gitee.com/icecat2233/picture/raw/master/20251228200136901.png" alt="image-20251228200135970" style="zoom:50%;" />
**拒绝策略**用的最多的只有第一种AbortPolicy
![image-20251228200427425](https://gitee.com/icecat2233/picture/raw/master/20251228200428737.png)
**任务队列:**
<img src="https://gitee.com/icecat2233/picture/raw/master/20251228200930260.png" alt="image-20251228200929336" style="zoom: 80%;" />
### 总结:
<img src="https://gitee.com/icecat2233/picture/raw/master/20251228200821304.png" alt="image-20251228200820075" style="zoom:50%;" />
### 案例:
```Java
public class Demo3 {
public static void main(String[] args) {
ThreadPoolExecutor tp = new ThreadPoolExecutor(
3,//核心数
6,//最大核心数
10,//空闲时间
TimeUnit.SECONDS,//时间单位
new ArrayBlockingQueue<>(10),//排队人数
Executors.defaultThreadFactory(),//线程对象任务工厂,基本为固定
new ThreadPoolExecutor.AbortPolicy()//拒绝策略,基本只用这个方法
);
for (int i = 1; i <17 ; i++) {
tp.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "调用了hhh");
}
});
}
tp.shutdown();
}
}
```
## 单例设计模式:
<img src="https://gitee.com/icecat2233/picture/raw/master/20251228204751280.png" alt="image-20251228204750037" style="zoom:50%;" />
两种方式:
**饿汉式:简单不烧脑**
直接创建出对象 而不是调用方法的时候再创建对象
**懒汉式:(延迟加载模式):**
<img src="https://gitee.com/icecat2233/picture/raw/master/20251228204928022.png" alt="image-20251228204926855" style="zoom:50%;" />