Thread常用的方法及线程状态原因解析

温馨提示:PC端观看,效果更佳!

本文两大部分:介绍一些Thread线程常用的方法,和解析线程的六大状态!

目录

一、线程常用的方法

介绍Thread类

1.开启线程

2.获取线程引用

3.休眠线程

4.中断线程

3.等待线程

二、线程状态

1.NEW

2.TERMINATED

3.RUNNABLE

4.WAITING

5.TIMED_WAITING

6.BLOCKED

7.状态总结(超级重要)


一、线程常用的方法

介绍Thread类

(1)这是一个线程类,用来实例化线程对象

(2)该类中,有很多方法。普通成员方法,可以使用对象的引用进行调用,像statr()方法等等;而静态方法,则需要通过类名去调用,如:Thread.sleep()等等。

(3)我们通过Thread来实例化对象,产生的对象,我们默认称为“线程对象”,start()之后,线程才产生。因此,类中拥有的各种属性方法,我们后面就默认称为该线程的属性和方法。

(4)线程,有哪些状态、属性,方法,本质上都是Thread中的;因此我们实例化出的线程,也就具有了。后续所说的线程,都是指 线程对象

1.开启线程

(1)方法:start()

(2)作用:当线程对象调用该方法之后,真正的线程才真正的被创建出来并且执行。

(3)实例

 public static void main(String[] args) throws InterruptedException {Thread t = new Thread("张三线程") {@Overridepublic void run() {System.out.println("111");}};t.start();}

在:该操作,只是创造出了线程对象

Thread t = new Thread("张三线程")

只有:start()之后,该线程才是真正创建并运行了起来(真正在系统中创造了PCB)

 t.start();

(4)start()注意事项

每一个线程对象,只可以start()一次。第二次start()操作就会出现异常

异常:非法的线程状态 

该线程状态:

原因:线程start()之后,被调度到cpu上执行,当线程中的任务执行完之后,就会被销毁了;此时线程(PCB)已经不存在了,但是Thread对象(t引用指向的对象)还存在。

2.获取线程引用

(1)作用:返回当前线程对象的引用(在哪个线程中调用,就返回哪个线程的)

(2)方法全貌:public static native Thread currentThread()

(3)返回自定义线程的引用

public static void main(String[] args) {Thread t = new Thread(()->{System.out.println(Thread.currentThread().getState());System.out.println("开启线程成功!");}) {};t.start();}

获取t线程的引用,并且调用该线程的状态

(4)获取主线程的引用

 public static void main(String[] args) {Thread t = Thread.currentThread();//此时t中存的是main线程的引用System.out.println("线程名字:"+t.getName());}

3.休眠线程

(1)方法:Thread.sleep()。很明显,这是一个静态方法,需要传参。

参数是整数,单位是ms。1000ms等于一秒

(2)作用:让线程休眠

(3)实例

public static int m = 4;public static void main(String[] args) {Thread t = new Thread(()->{while (true) {try {Thread.sleep(1000);m--;} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(m+"秒后结束t线程");if(m == 1) break;}System.out.println("t线程结束");});t.start();}

作用:每循环一次,就会休眠一秒,当休眠三秒后,线程就会结束。

(4)使用的注意实现1

1)在重写的run方法中

原因:在方法重写的时候,要求方法前面是一样的,run方法的父类是没有抛出异常的,所以run方法也不能抛出异常。所以sleep异常处理选择时,就不能抛出异常,只能捕获异常。

2)在外面

(5)sleep的注意事项2

sleep控制的是线程的休眠时间,而不是两个代码之间的时间

在时间上,并不是1000ms.

得出一个小结论:sleep结束之后,线程不一定会马上被调度会cpu上执行。

4.中断线程

更加合理的说法是说,终止一个线程。按理来说,当线程开启的时候,就会一直执行,直到线程的任务结束。但是有时候,需要停止线程,就需要一些操作去执行了。而终止线程,只是起到提醒的作用,线程是否要终止,还要看线程本身。

目前有两种方式:

(1)通过共享的标记来进行沟通(2)调用interrupt()方法来通知

2.1.第一种实现

(1)标志正确写法

    public static boolean isRunning = true;public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while (isRunning) {System.out.println("线程正在执行!");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("线程结束了");});t.start();System.out.println("3s后结束线程");Thread.sleep(1000);isRunning = false;}

实现手段:通过改变循环的条件来终止循环,进而结束线程。

(2)缺点

1)该标志变量要定义在main方法外面,也就是全局变量;如果定义在里面,会被内部类捕获到,从而报错。

2)这种终止线程写法的缺点 ,即使循环条件不符合了,需要结束循环,但是由于上一次循环进入时,线程正在sleep中,导致无法即使终止线程。

2.2.第二种实现

(1)简介:使用Thread的三个方法来配合实现。下面介绍

方法作用
public void interrupt()修改标志位(哪个线程调用就修改)
public static native Thread currentThread()获取当前线程的引用
public boolean isInterrupted()线程中自带的标志位,默认值为false

(2)代码实现

 public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while (!Thread.currentThread().isInterrupted()) {System.out.println("线程正在执行!");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("线程结束了");});t.start();System.out.println("3s后结束线程");Thread.sleep(1000);t.interrupt();}

代码是结束了,但是抛出了异常。是因为唤醒sleep等阻塞的方法,即使线程在sleep中,也能即使结束线程(就是相比于第一种方法的优势)。设置成false之后,则会让sleep抛出一个InterruptedException异常,不需要等待sleep,进而结束了。

如果更改sleep抛出的异常,进而可以控制线程。

(3)提醒线程终止,但是不想结束

 public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while (!Thread.currentThread().isInterrupted()) {System.out.println("线程正在执行!");try {Thread.sleep(1000);} catch (InterruptedException e) {//throw new RuntimeException(e);e.printStackTrace();}}System.out.println("线程结束了");});t.start();System.out.println("3s后结束线程");Thread.sleep(1000);t.interrupt();}

代码没有结束,抛出一个异常后继续执行了代码。

原因:在触发interruptd的时候,而线程正在sleep的时候,会唤醒正在sleep,并且把interrupt修改的标志位又修改回来(又改回false)。前面因为没有修改抛出的异常,而直接把线程终止了。

(4)提醒线程终止,马上终止

 public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while (!Thread.currentThread().isInterrupted()) {System.out.println("线程正在执行!");try {Thread.sleep(1000);} catch (InterruptedException e) {//throw new RuntimeException(e);//e.printStackTrace();System.out.println("自愿结束线程");break;}}System.out.println("线程结束了");});t.start();System.out.println("3s后结束线程");Thread.sleep(1000);t.interrupt();}

(5)提醒线程终止,等会结束

public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while (!Thread.currentThread().isInterrupted()) {System.out.println("线程正在执行!");try {Thread.sleep(1000);} catch (InterruptedException e) {System.out.println("我先打印完1234再结束");System.out.println(1);System.out.println(2);System.out.println(3);System.out.println(4);break;}}System.out.println("线程结束了");});t.start();System.out.println("3s后结束线程");Thread.sleep(1000);t.interrupt();}

3.等待线程

等待线程有三个重载的方法,前面的两个比较常用

方法说明
public void join()等待线程结束(死等)
public void join(long millis)等待线程结束,最多等millis毫秒
public void join(long millis,int nanos)同2,但可以更高精度(因此容易出错)

线程等待的意义:多线程中,调度顺序是无序的,因此每个线程的执行时间和结束时间是不确定的。引用线程等待,就可以控制线程结束的先后顺序

下面以join()为主要介绍。

3.1.join()

(1)没有等待时

 public static void main(String[] args)  {Thread t = new Thread(()->{while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t");}});t.start();System.out.println("main线程");}

此时,是main线程已经结束,但是t线程没有结束。

(2)引入等待

 public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t");}});t.start();t.join();System.out.println("main线程");}

通过代码的结果可以看到,没有执行后面的打印语句。这样的意思是:main线程需要等待t线程结束后才能结束,也就是结束t.join()语句才行。

此时,main线程在等待t线程,也就是等待状态。代码无法直接观看,借助调用栈来观看

(3)等待解析

哪个线程调用join,哪个线程就是要先执行结束的。准确的来说:在A线程里面,B线程调用join,那么线程结束的顺序就是 B-->A,也就是线程A会等待线程B先结束

(4)深入理解

上面的代码中,在main中调用t.join(),有三种情况。

1)如果线程t此时已经结束了,此时的join就会立即返回,相当于join没气作用

2)如果线程t还没结束,此时main线程就会阻塞等待t线程结束,直到t线程结束之后,join才会解除阻塞,继续执行main

3)当执行t.join时,t线程还没开始,就会直接跳过t.join(),相当于没起到作用

下面介绍上面三种情况,顺便多介绍两种情况。

第一种情况:t.join时,t线程已经结束了(只有t线程和main线程)

当代码执行到t.join()时,t线程已经被销毁了,所以执行join时就直接返回了,相当于没有

第二种情况:正常起到作用(只有t线程和main线程)

当执行到t.join()时,t线程还没结束,此时就会main线程就会阻塞等待,直到t线程结束之后才会继续执行

第三种情况:t线程还没开始(只有t线程和main线程)

这就是当执行到t.join()时,t线程还没开始执行

第四种情况:三个线程嵌套等待(t1线程、t2线程、main线程)

预期结束顺序:t2 -> t1 -> main 

 public static void main(String[] args) throws InterruptedException {Thread t2 = new Thread(()->{for (int i = 0; i < 3; i++) {System.out.println("t2");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t1 = new Thread(()->{try {Thread.sleep(500);//确保t2线程此时已经启动t2.join();//t1线程阻塞等待t2线程结束后再执行} catch (InterruptedException e) {throw new RuntimeException(e);}for (int i = 0; i < 3; i++) {System.out.println("t1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t1.start();t2.start();t1.join();//main线程阻塞等待t1线程结束再继续执行System.out.println("main end");}

得出一个小结论:在A线程中使用B.join(),那么一定是B线程先结束,A线程后结束(join阻塞A线程);但是A线程中同时使用B.join()和C.join(),B线程和C线程之间是并发执行,A阻塞等待的时间是Math.max(B线程的时间,C线程的时间)

执行结果:

第五种情况:main线程也可以join()操作

要想做到main线程先结束,就要拿到主线程的引用

public static void main(String[] args) throws InterruptedException {Thread mainT = Thread.currentThread();//拿到main线程的引用System.out.println(mainT.getName());Thread t = new Thread(()->{try {mainT.join();//main线程先结束,t线程才会继续执行} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t end");});t.start();Thread.sleep(2000);System.out.println("main end");}

由此可见,main线程也是可以join的

由于join()是一个死等的方法,只有t线程不结束,还没的代码就不会执行。这种写法很不友好。

3.2.join(long millis)

(1)这是一种带有时间的等待,参数就是需要等待的时间,如果超过了这个时间就不会继续执行下去,进而去执行后面的代码。

 public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("t");}});t.start();t.join(3000);System.out.println("main end");}

t线程是一个死循环线程,永远不会结束,如果是死等的join,那么main线程永久不会结束。但是这是一个带有时间的超时等待,过了这个时间就不会再继续等待下去

(2)如果join等待3秒,而t线程执行2秒,也会提前结束join,并不是真的会等待3秒

4.方法小结(超级重要)

注:方法括号中的ms代表毫秒

方法名称方法方法作用
开始一个线程start()自定义的线程调用后,才代表该线程启动
获取当前线程的引用currentThread()可以获取当前线程的一个引用
休眠线程sleep(ms)让当前线程休眠指定时间
中断线程isInterrupted()、interrupted()提醒线程是否要终止
等待线程join()--无参方法调用该方法的线程提前结束,阻塞
join(ms)--带有参数方法在嵌套该线程的那个线程

 

二、线程状态

线程的状态,也是PCB中的状态。粗分的话有四个状态,细分是六个状态。下面我们以六个状态来介绍。

状态名字
NEW新建状态
TERMINATED终止态
RUNNABLIE就绪态
WAITING死等状态
TIMED_WAITING带有超时时间的等待
BLOCKED因锁竞争的阻塞

后面三种,大的方向都是阻塞状态

下面每个状态一一介绍,产生状态的原因。每种状态都会用代码使用,和在调用堆栈中观察,如果可以使用代码观察(使用getState()查看线程状态),也会一起展示。

1.NEW

(1)小写:new  中文名字:新建态

(2)产生时间/原因:在Thread对象产生后,为start()之前

(3)线程状态解释:此时的线程并未真正的产生,只存在硬盘中,当start()后,线程才真正产生(处于cpu上)

(4)代码观察状态

public static void main(String[] args) {Thread t = new Thread();System.out.println(t.getState());
}

(5)使用调用堆栈观看

 public static void main(String[] args) throws InterruptedException {Thread t = new Thread("ttttt");System.out.println(t.getState());Thread.sleep(30000);}

让main线程休眠30秒,好让观察

此时,只能看到main线程,而看不到ttttt线程,原因就是此时只是创造出Thread对象,线程处于新建态,还未调度到cpu上执行

2.TERMINATED

(1)小写:terminated  中文:终止态

(2)产生原因:线程开始后,线程完成了任务之后,线程从pcb中被销毁

(3)代码观察

1)第一种

public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{System.out.println("执行完这个语句t线程就结束");});System.out.println(t.getState());t.start();Thread.sleep(3000);System.out.println(t.getState());}

等待三秒后再去获取t线程的状态

2)第二种实现

 public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{System.out.println("执行完这个语句t线程就结束");});System.out.println(t.getState());t.start();t.join();System.out.println(t.getState());}

使用t.join(),就可以保证在t线程结束之后再去执行后面的语句(推荐)

(4)使用调用堆栈观察

使用堆栈无法观察,因为这个状态是线程终止态,线程已经被销毁了,不复存在。

3.RUNNABLE

(1)小写:runnable  中文:就绪状态

(2)产生原因有两种

1)这个线程正在CPU上执行

2)这个线程不在CPU上执行,但是可以随时调度到CPU上执行

下面我们只去研究第一种,因为第二种我们无法干预,也无法展示

(3)代码观察

 public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{try {Thread.sleep(20000);} catch (InterruptedException e) {throw new RuntimeException(e);}});System.out.println(t.getState());t.start();System.out.println(t.getState());}

此时线程还是休眠中,任务还没结束,因此展示出来的就是RUNNABKE

(4)在调用堆栈中

 public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while (true) {}});System.out.println(t.getState());t.start();System.out.println(t.getState());}

在t线程中,我们使用死循环的写法。如果是休眠时间,但调用堆栈中会是:带有超时时间的等待状态。

4.WAITING

(1)小写:waiting  名称:等待

(2)原因:由于死等进入的等待状态。其中有两个典型的例子

1)由于join()进入的死等状态  

2)由于wait()进入的死等状态(在线程安全问题部分会有学习)

(3)因join()进入的WAITING状态

由于要执行完t.join()才会去执行后面的语句,所以代码层面观察不到线程的状态

 public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("1");}});t.start();t.join();System.out.println(Thread.currentThread().getState());}

使用调用堆栈观察:

(4)因wait()进入的等待状态

这个方法居然做什么的,目前先不做具体的解释

可见,线程的WAITING状态是由于两种死等的方法造成的

5.TIMED_WAITING

(1)名称:带有超时时间的等待

(2)产生原因:由带参数的:join()、sleep()、waiting()方法而进入的带有超时时间的等待。

(3)第一种:由sleep()进入的等待

(4)第二种:带有时间的join()

(5)第三种:带有时间的wait()

以上就是进入TIMED_WAITING状态的三种方式

6.BLOCKED

(1)原因由来:由于锁竞争产生的阻塞

(2)代码展示

public static void main(String[] args) {String str = "520";Thread t1 = new Thread(()->{synchronized (str) {while (true) {}}});t1.start();Thread t2 = new Thread(()->{synchronized (str) {System.out.println("1");}});t2.start();System.out.println(t2.getState());}

由于t1线程已经对str对象上锁,当t2再次想对str对象加锁时,就会产生互斥,从而进入阻塞状态。

7.状态总结(超级重要)

7.1.部分总结

(1)RUNNABLE状态

原因1:这个线程正在cpu上执行,也就是线程正在执行

原因2:这个线程暂时未在cpu上执行,但是可以随时调度到cpus上执行

(2)阻塞状态

阻塞状态的作用:进入阻塞状态的线程,暂时不能调度到cpu上执行,直到满足一定的条件,才会重新进入就绪状态。

阻塞状态有三个:WAITING、TIMED_WAITING、BLOCKED

三种状态都是阻塞状态,但是产生的原因不一样

7.2.表格总结

 

状态产生原因1产生原因2产生原因3
NEWThread对象创建时
TERMINATED内核中的线程(PCB)被销毁(线程结束时)
RUNNABLE线程正在cpu上运行时线程可以随时调度到cpu运行(不可干预)
WAITINGjoin()wait()
TIMED_WAITINGsleep(参数)join(参数)wait(参数)
BLOCKED对同一个锁竞争


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/781839.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ERP原理与应用】用友U8实验

实验一、系统管理与基础设置 实验内容&#xff1a; 一、核算体系的建立 好友软件公司是一家软件制造和系统集成企业&#xff0c;其产品面向国内外市场&#xff0c;自 2019 年 3 月公司开始使用 ERP 软件管理业务。软件操作员有三位&#xff0c;黄红是账套 主管&#xff0c;张…

mysql进阶知识总结

1.存储引擎 1.1MySQL体系结构 1).连接层 最上层是一些客户端和链接服务&#xff0c;包含本地sock通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念&#xff0c;为通过认证…

机器学习基础——模型评估与选择(部分)

目录 一、前言&#xff1a;误差与拟合 &#xff08;一&#xff09;经验误差 &#xff08;二&#xff09;过拟合、欠拟合 二、评估方法 &#xff08;一&#xff09;评估总体的思路 &#xff08;二&#xff09;如何划分训练集和测试集 1.留出法 2.k折交叉验证 3.自助法 …

代码学习记录31---动态规划开始

随想录日记part31 t i m e &#xff1a; time&#xff1a; time&#xff1a; 2024.03.29 主要内容&#xff1a;今天开始要学习动态规划的相关知识了&#xff0c;今天的内容主要涉及四个方面&#xff1a; 理论基础 ; 斐波那契数 ;爬楼梯 ;使用最小花费爬楼梯。 理论基础 509. 斐…

SQLServer sys.default_constraints介绍

sys.default_constraints 是 SQL Server 的系统视图&#xff0c;它包含了数据库中所有默认约束的信息。默认约束是数据库对象&#xff08;如表中的列&#xff09;的约束&#xff0c;它为列定义了一个默认值&#xff0c;当在插入新行时没有为该列提供值时&#xff0c;将使用这个…

【保姆级教程】DeepLabV3+语义分割:训练自己的数据集

一、DeepLabV3图像语义分割原理 DeepLabV3架构采用扩张卷积&#xff08;也称为空洞卷积&#xff09;来捕捉多尺度信息&#xff0c;从而在不损失空间分辨率的情况下实现对图像的精细分割。 二、DeepLabV3代码及预训练权重下载 2.1 下载deeplabv3代码 这里使用的是B站大佬Bu…

axios+springboot上传图片到本地(vue)

结果&#xff1a; 前端文件&#xff1a; <template> <div> <input type"file" id"file" ref"file" v-on:change"handleFileUpload()"/> <button click"submitFile">上传</button> </div&g…

基于ssm的留学生交流互动论坛网站(java项目+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的留学生交流互动论坛网站。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 留学生交流互动论坛网站…

Solana 2024 投资新风口:挖掘 DeFi、硬件开发与交易创新

将区块链的技术红利带给所有用户&#xff0c;Solana 自 2017 年诞生以来就致力于赋予开发者、消费者、投资人等各路人士的优越应用体验。在“以太坊杀手”林立的公链竞争阶段&#xff0c;Solana 凭借高性能公链的独特定位&#xff0c;朝着去中心化、安全性、低成本的目标不断精…

刷爆LeetCode:两数之和 【1/1000 第一题】

&#x1f464;作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 作者专栏每日更新&#xff1a;LeetCode解锁1000题: 打怪升级之旅https://blog.csdn.net/cciehl/category…

设计模式之建造者模式精讲

也叫生成器模式。将一个复杂的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 在建造者模式中&#xff0c;有如下4个角色&#xff1a; 抽象建造者&#xff08;Builder&#xff09;&#xff1a;用于规范产品的各个组成部分&#xff0c;并进行抽象&…

c++使用类的一些注意事项

前言&#xff1a; 本篇内容为前面的补充&#xff0c;介绍了我们使用类时需要注意些什么以及一些编译器的优化&#xff0c;可能有些理解不到位或者错误&#xff0c;请斧正。 目录 前言&#xff1a; 1.再谈构造函数 2.&#xff08;c98&#xff09;隐式类型转换中的编译器的优…

Codeforces Round 934 (Div. 2) D. Non-Palindromic Substring

题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn 1e6 5, inf 1e9, maxm 4e4 5; co…

【初阶数据结构】——牛客:CM11 链表分割

文章目录 1. 题目介绍2. 思路分析3. 代码实现 1. 题目介绍 链接: link 这道题是给我们一个链表和一个值X &#xff0c;要求我们以给定值x为基准将链表分割成两部分&#xff0c;所有小于x的结点排在大于或等于x的结点之前。 最终返回重新排列之后的链表的头指针。 2. 思路分析…

Redis 的慢日志

Redis 的慢日志 Redis 的慢日志&#xff08;Slow Log&#xff09;是用于记录执行时间超过预设阈值的命令请求的系统。慢日志可以帮助运维人员和开发人员识别潜在的性能瓶颈&#xff0c;定位那些可能导致 Redis 性能下降或响应延迟的慢查询。以下是 Redis 慢日志的相关细节&…

hcip综合实验2

目录 实验拓扑&#xff1a; 实验要求&#xff1a; 实验思路&#xff1a; 实验步骤&#xff1a; 1.配置设备接口IP 2.通过配置缺省路由让公网互通 3.配置ppp 1.R1和R5间的ppp的PAP认证&#xff1b; 2.R2与R5之间的ppp的CHAP认证; 3. R3与R5之间的HDLC封装; 4.构建R1、…

K8S故障处理指南:pod驱逐问题处理

更多技术博客,请关注微信公众号:运维之美 在K8S集群故障处理过程中,你可能遇到过pod的各种状态,Evicted状态代表你的K8S环境遇到了资源驱逐的问题,本节通过对驱逐问题的解决,参数的调整,问题的处理思路,希望给你解决此类问题提供帮助。 一、pod驱逐问题 pod出现状态为…

如何系统的自学python?

系统地自学Python是一个循序渐进的过程&#xff0c;以下是一份详细的指南&#xff0c;帮助你从零开始逐步掌握这门语言&#xff1a; 1、了解Python及其应用场景&#xff1a; 阅读关于Python的简介&#xff0c;理解它为何流行&#xff0c;以及在哪些领域&#xff08;如Web开发…

GitHub | Pages 部署 Vue 项目但页面空白,报错:net::ERR_ABORTED 404 (Not Found)

目录 报错信息 解决方法 报错信息 如下所示&#xff08;地址已盲&#xff09;&#xff1a; 控制台报错说找不到这些资源&#xff0c;但是 dist 目录下都有这些 JS 文件啊&#xff0c;这是为什么&#xff1f; 解决方法 在 Vue 项目的 vue.config.js 文件中&#xff0c;添加 …

FANUC机器人故障诊断—报警代码更新(三)

FANUC机器人故障诊断中&#xff0c;有些报警代码&#xff0c;继续更新如下。 一、报警代码&#xff08;SRVO-348&#xff09; SRVO-348DCS MCC关闭报警a&#xff0c;b [原因]向电磁接触器发出了关闭指令&#xff0c;而电磁接触器尚未关闭。 [对策] 1.当急停单元上连接了CRMA…