new commit
This commit is contained in:
467
线程.md
Normal file
467
线程.md
Normal file
@@ -0,0 +1,467 @@
|
||||
# 线程
|
||||
|
||||
## 进程和线程
|
||||
|
||||
### 进程介绍:
|
||||
|
||||

|
||||
|
||||
<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%;" />
|
||||
Reference in New Issue
Block a user