467 lines
13 KiB
Markdown
467 lines
13 KiB
Markdown
# 线程
|
||
|
||
## 进程和线程
|
||
|
||
### 进程介绍:
|
||
|
||

|
||
|
||
<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);
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 注意:
|
||
|
||

|
||
|
||
### 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;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 尽量选择后两个,拓展性更好
|
||
|
||
## 线程的方法
|
||
|
||

|
||
|
||
### 名字相关:
|
||
|
||

|
||
|
||
### 休眠线程:
|
||
|
||
<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守护t1,t1线程任务结束,t2也结束(不是立刻结束,t2会在苟活一会儿)
|
||
|
||
哪个线程对象调用setDaemon方法,这个线程就是守护线程
|
||
|
||
## 线程的安全与同步
|
||
|
||
<img src="https://gitee.com/icecat2233/picture/raw/master/20251227180107783.png" alt="image-20251227180059497" style="zoom: 50%;" />
|
||
|
||
### 1.同步代码块:
|
||
|
||

|
||
|
||
**使用同步代码块指定锁对象时,用类的字节码对象**
|
||
|
||
**共享数据要用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
|
||
|
||

|
||
|
||
**任务队列:**
|
||
|
||
<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%;" /> |