当前位置: 首页 > news >正文

多线程(基础)

  前言👀~

上一章我们介绍了什么是进程,对于进程就了解那么多即可,我们作为java程序员更关注线程,线程内容比较多,所以我们要分好几部分才能讲完

目录

进程的缺点

 多线程(重要)

进程和线程的区别(经典面试题)

java如何进行多线程编程?

创建线程的方式(面试题)

继承Thread类(来自java.lang包下)

使用匿名内部类继承Thread类重写run

实现Runnable接口

使用匿名内部类实现Runnable接口重写run

使用lambda表达式创建线程(推荐)

Thread 类及常见方法

Thread类的构造方法

Thread类的常见属性

启动线程

中断线程

等待线程

查看线程状态


如果各位对文章的内容感兴趣的话,请点点小赞,关注一手不迷路,如果内容有什么问题的话,欢迎各位评论纠正 🤞🤞🤞

12b46cd836b7495695ce3560ea45749c.jpeg

个人主页:N_0050-CSDN博客

相关专栏:java SE_N_0050的博客-CSDN博客  java数据结构_N_0050的博客-CSDN博客  java EE_N_0050的博客-CSDN博客


进程的缺点

多进程编程的缺点:进程太重量效率不高,创建进程和销毁进程和调度进程消耗的时间都是比较多的(消耗在申请资源上),因为我们知道进程是系统资源分配的基本单元,所以在给进程分配资源的时候是一个大活。拿分配内存说,操作系统内部也有一定的数据结构,用来管理空闲的内存,当进程申请内存空间的时候,操作系统就会从这个数据结构中找到大小合适空闲的内存返回给进程。这里的数据结构可以提高一定的效率,但是总体来说和线程相比还是比较耗时的。同时频繁创建和销毁进程和进程切换是一个开销很大的操作,多进程和多线程都能实现并发编程,线程比进程更轻量。有些任务场景需要 “等待 IO”, 为了让等待 IO 的时间能够去做⼀些其他的工作, 也需要用到并发编程. 其次,虽然多进程也能实现 并发编程, 但是线程比进程更轻量


 多线程(重要)

进程想要执行任务就需要依赖线程线程不能独立存在,需要依附于进程(进程包含线程,进程可包含一个线程也可包含多个线程),一个进程在最开始的时候,至少要有一个线程(主线程),这个线程负责完成执行代码的工作,我们也可以根据需要创建多个线程,从而实现"并发编程"的效果换句话说,就是进程中的最小执行单位就是线程

线程也称轻量级线程(创建、销毁、调度都比进程快),每个线程就是一个独立的 "执行流"(因为在执行用户写的代码)可以独立的执行一些代码,每一个线程可以执行一系列的操作(也就是代码)

更好的理解线程,还是拿之前在进程举的演员的例子,一个舞台可以有多个演员,但是呢这个多个演员来自不同的剧组,这里面的演员就是线程,剧组就是进程。在我们之前谈的进程调度都是基于一个进程只有一个线程,可以理解为之前每个剧组都只有一个演员。实际上,一个进程可以有多个线程,每个线程都可以独立进行调度。之后谈到进程调度的话,不是调度整个进程,而是调度进程中的每一个线程。就比如说这个导演叫这个剧组的所有人来拍戏,所有的演员由导演进行分配角色、上场时间、台词等,相当于线程也有状态、优先级、上下文、记账信息

下面有图更好理解多线程
 
一个工厂代表一个进程,一个生产线代表一个线程,我们之前提到的多进程是下面这样子的 


下面这样是我们说的多线程,一个进程中有多个线程,同个工厂(共用资源)两个生产线(多线程)提高了效率


下面这么多人吃100个坤,适当的线程数目(里面的人)能提高效率,但是线程数目过多的情况,效率会降低并且造成线程冲突(线程不安全)


当人数过多且有人吃不到坤的时候,生气了把鸡全扔了,此时引发线程异常,如果我们没有处理好,可能会导致整个进程崩了,其他线程也会随之消失


总结:一个进程使用PCB来表示,一个进程可以使用一个PCB表示也可与使用多个PCB表示,每个TCB对应一个线程(可以理解PCB中包含TCB),并且每个线程都有这些信息(状态、优先级、上下文、记账信息,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈)辅助调度,除此之外,前面说到的属性pid是相同的,内存指针、文件描述符表也是共用一份的,根据这些信息我们可以得出线程的特点:每个线程都可以独立去cpu上调度执行、同一个线程的多个进程之间共用一份内存空间和文件资源,所以我们创建线程的时候不需要像进程一样申请资源(但是呢创建第一个线程的时候,相当于和进程一起创建的,所以我们要去申请资源,这里申请资源算在进程头上。后续再创建线程的话就是共享同一份了),我们直接用系统给进程分配好的资源,这样大大提高了我们的效率和节省开销。综上所述我们可以得出进程是资源分配的基本单位,线程是CPU 调度执行的基本单位

每个线程都是独立调度的,在调度的过程中,系统就不考虑 进程 这样的概念了。所以就是不同进程中的线程可以被轮番调度,每个线程只有获得 CPU 的使用权才能执行指令。所谓多线程的并发运行,其实是指从宏观上看,各个线程轮流获得 CPU 的使用权,分别执行各自的任务。


进程和线程的区别(经典面试题)

1.线程比进程更轻量、高效,线程不需要申请资源,和同一进程共用一份,省去了申请资源的开销

2.同一个进程内线程和线程之间会有影响(线程不安全和线程异常),一个线程崩了可能导致其他线程受到影响最终导致进程崩了。进程和进程之间具有独立性

3.线程依附于进程,一个进程至少有一个线程(主线程),也可以有多个线程

4.线程是调度执行的基本单位,进程是资源分配的基本单位


java如何进行多线程编程?

线程是操作系统的概念,操作系统提供了一套API来操作线程,java对操作系统提供的API进行封装(跨平台),我们学java的只需要掌握java封装过后的这套API就可以操作线程了

进程和进程之间能并发执行实现并发编程,线程和线程之间也能实现并发执行实现并发编程,我们学java的更侧重线程之间的并发执行

创建线程的方式(面试题)

继承Thread类(来自java.lang包下)

创建Thread对象,我们就可以操作 操作系统内部的线程了。以及重写入口方法run(描述了该线程要执行的任务)

class MyThread extends Thread {@Overridepublic void run() {System.out.println("我开始工作了");System.out.println("我结束工作了");}
}public class test1 {public static void main(String[] args) {Thread thread = new MyThread();thread.start();System.out.println("我是主线程");}
}

输出:不确定

再来看下面这段代码,猜一下输出顺序

class MyThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("thread线程正在工作");}}
}public class test1 {public static void main(String[] args) {Thread thread = new MyThread();thread.start();while (true) {System.out.println("主线程正在工作");}}
}

输出:交替输出


为什么呢?我们也不知道这两个线程是同时执行的还是交替执行的(同一个核心上执行,还是分别在两个核心上执行),所以我们统称并发(并行+并发),实现并发编程的效果,为什么要实现并发编程?(充分利用多核cpu的资源)。

注意:打印顺序不一定,操作系系统对于多个线程的调度顺序是不确定的,随机的。虽然有先后顺序但是谁先谁后我们是不确定的(重要),这个随机取决于操作系统对于线程调度的模块(调度器)的具体实现

接着再来看下面这段代码,猜一下输出顺序

class MyThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("thread线程正在工作");}}
}public class test1 {public static void main(String[] args) {Thread thread = new MyThread();thread.run();while (true) {System.out.println("主线程正在工作");}}
}

输出:thread线程正在工作   不只一条哈

原因:T.run 这种时候只有一个主线程,因为我们没有创建一个新的进程。等run这个方法结束后,才会执行后面的代码,相当于只有一个执行流,只能依次执行循环。相当于就是main线程在执行它的run方法,就跟我们在main方法中平常创建一个类然后调用方法一样,main线程在工作

不信的话代码拿去自己试试,然后用jdk中自带的工具jconsole,里面其他线程是JVM创建的

使用匿名内部类继承Thread类重写run

同样创建Thread对象,我们就可以操作 操作系统内部的线程了。以及重写入口方法run(描述了该线程要执行的任务)

public class test1 {public static void main(String[] args) {Thread thread = new Thread() {@Overridepublic void run() {System.out.println("我是匿名内部类");}};thread.start();System.out.println("我是主线程");}
}

实现Runnable接口

实现Runnable接口,它就表示的是一个可以运行的任务,所以还是需要创建线程来完成这个任务。这样理解我写了个任务,丢给线程去完成,但是我们要先把线程创建出来才能去完成

class MyRunnable implements Runnable {@Overridepublic void run() {while (true) {System.out.println("我是Runnable接口");}}
}public class test1 {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);thread.start();while (true) {System.out.println("主线程正在工作");}}
}

使用Runnable接口和继承Thread类的区别:主要是为了解耦合,使用Runnable接口相当于跟线程拆分开,把任务抽离出来,可以把这个任务丢给任意一个线程去完成,可以用在需要重复完成这个任务的场景,直接继承Thread类就不行,它更适合完成一次性的任务

还有关于创建一个线程的时候,有两个关键的操作。一个是明确线程要执行的任务,我们更关注任务本身,如果这个任务就只是执行一段简单的代码至于用什么方式实现这个任务没什么区别。如果遇到复杂的任务有些方式可能就完成不了,这时候我们需要用其他的方式去完成,这时候我们把任务提取出来,我们可以自己选择指定的方式去完成这个任务    。另外一个操作就是通过调用系统API创建出线程。

使用匿名内部类实现Runnable接口重写run

public class test1 {public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("我是匿名内部类");}}) {};thread.start();System.out.println("我是主线程");}
}

使用lambda表达式创建线程(推荐)

public class test1 {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("我是lambda表达式");});thread.start();System.out.println("我是主线程");}
}

除了上面的方式之外,还有其他的方式,后续讲解,还有一个点需要清楚就是创建Thread类的时候并没有真正创建线程,只有在调用start方法的时候调用系统API去创建线程的时候才算认识


Thread 类及常见方法

Thread类的构造方法

在Thread类源码里有个构造方法可以设置线程的名字,其他的就没什么好介绍的了

public class test1 {public static void main(String[] args) {Thread thread = new Thread(() -> {while (true) {System.out.println("我是lambda表达式");}}, "我叫线程A");thread.start();}
}

为什么这里没有显示main线程呢?因为main线程执行完了,线程的入口方法执行完了,这个线程自然就销毁了。对于主线程来说,入口方法就是main方法,它调用系统API去创建完线程之后就执行完了。所以如果线程都执行完了,进程也就结束了但只要有一个线程还在执行,进程就不会结束
 


Thread类的常见属性


1.ID:线程的身份标识就是用来区分线程的,类似进程的pid,只不过这里的ID是java提供的,不是系统api提供的

2.getState()方法:获取线程状态,后面有讲到

3.isDaemon()方法判断是否为后台线程(守护线程),守护线程就是用来告诉JVM,我的这个线程不重要不需要等待它运行完才退出,让JVM喜欢什么时候退出就退出。前台线程(非守护线程)就是告诉JVM,这个线程没执行完成之前,你不能退出。默认情况一个线程是前台线程守护进程(后台进程),默认情况一个线程是前台线程我们可以通过setDameon()方法去设置,这么设置之后主线程执行完后,没有其他前台线程了,这个进程自然也就结束了

public class test1 {public static void main(String[] args) {Thread thread = new Thread(() -> {while (true) {System.out.println("我是lambda表达式");}}, "我叫线程A");thread.setDaemon(true);//设置thread线程为守护线程thread.start();}
}

4.isAlive()方法:Thread对象的生命周期要比系统内核中的线程更长,线程没了Thread对象还在,我们要以系统内核中的线程为主。所以我们使用isAlive()进行判断,判断系统内核中的线程有没有结束,结束返回false,没结束返回true。简单的理解为 run 方法是否运行结束了

public class test1 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("我是lambda表达式");}, "我叫线程A");System.out.println(thread.isAlive());thread.start();System.out.println(thread.isAlive());Thread.sleep(2000);System.out.println(thread.isAlive());}
}

输出:false true 我是lambda表达式 false

5.isInterrupted()方法:用来判断线程是否被中断,怎么判断呢?Thread内部有一个标志位进行判断。下面会讲到


启动线程

使用start()方法创建线程

start方法和run方法的区别:非常直白的说,你可以把run看作是任务,start是叫人过来完成这个任务的。专业点说就是start方法通过调用系统API在系统内核中创建线程然后执行run方法中的代码。run方法会在线程创建好后自动被被调用


中断线程

中断一个线程(终止/打断),让一个线程停止运行(销毁),在java中销毁/终止一个线程做法比较唯一(这个唯一不是说只有一个方法,而是说销毁一个进程是让run方法快点执行完),让run方法快点执行完。在C++中是可以直接强制终止一个线程的运行,就比如你打开一个文本编辑器输入一段信息,输入一半直接给你干没了

先补充两个方法currentThread()方法和sleep()方法后面要用到

获取当前线程引用:currentThread()方法返回当前线程对象的引用,哪个线程调用这个方法就获取哪个线程对象的引用

休眠当前线程:sleep()方法让线程睡觉的,你可以设置睡多久,然后时间到了系统把它叫醒(阻塞->就绪),注意睡醒之后不会马上回到cpu上运行,要排队,这里会涉及调度所以会有一定的开销。就是你睡醒了需要一点时间缓缓才能去工作。

interrupt()方法:使用interrupt()方法设置标志位,前面说了Thread内部有一个标志位用来判断线程是否结束,调用这个方法就把这个标志位设置成true。这样即使我们还在执行sleep方法,它也会被强制唤醒。

来猜猜下面执行代码线程会是什么状态以及输出什么

public class test1 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("hello");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});thread.start();Thread.sleep(3000);thread.interrupt();}
}

答案是输出几个hello后报异常,然后说说过程,这个线程先执行sleep方法,然后这个线程处于睡眠,然后你使用了interrupt()方法设置把标志位为true,把这个线程唤醒了,那么这个线程就会继续工作,除非你不让它睡眠并且设置标志位为true。举个例子本来你在上班,然后突然有点困了,你同事让你睡会,结果领导来了你同事赶紧把你叫醒,你立马起来了。

使用interrupt()方法搭配sleep方法这样设置的标志位就像没效果一样,没有把你的线程中断,为什么这样设定呢?java期望线程收到中断的信息的时候,我们能够自己决定接下来要怎么处理,这样可以让我们在开发中有更多的操作空间,前提是通过异常的方式去唤醒。比如你打游戏女朋友叫你陪她去逛街,你可以直接关掉游戏陪她去,也可以说等我打完这把,还可以当个聋子啥也没听见。

public class test1 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("hello");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();
//            第一种   System.out.println("一直工作");
//                    
//            第二种   System.out.println("工作一会休息了");
//                    break;
//                    
//            第三种   break;}}});thread.start();Thread.sleep(3000);thread.interrupt();}
}

等待线程

使用join()方法,让一个线程等待另外一个线程执行结束再执行。前面说线程并发执行的时候,执行的顺序是不确定的随机的,此时我们可以通过这个方法来控制线程结束的顺序。并且我们可以设置等待时间,如果没有设置等待时间,默认的话这个线程会一直等到那个线程执行结束后才会执行自己的任务,类似舔狗有一直舔的也有舔一段时间不舔了

join方法的工作过程:

1.如果主线程正在运行,主线程中调用了A.join方法,此时主线程进入阻塞状态,A线程执行完,主线程才会解除完成接下来的任务

public class test1 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("我先干完活,你再干");}});thread.start();System.out.println("我要干活了");thread.join();System.out.println("轮到我干活了");}
}

输出结果

2.如果主线程任务已经执行完了,再调用A.join方法,就不用进入阻塞状态了,直接结束了

public class test1 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("我先干完活,你再干");}});thread.start();System.out.println("我马上干完不给你机会干");thread.join();}
}

输出结果


查看线程状态

和进程一样,线程也有运行、就绪、阻塞状态。真正在系统调度的还是线程,线程是调度执行的基本单位

在java中,给线程赋予了一些其他的状态:

1.NEW:Thread对象已经存在了,但是系统线程还没创建,也就是还没调用start方法

2.RUNNABLE:就绪状态,这里有两种表示,一种是在cpu上执行了,另一种是正等着去cpu上执行

3.TIMED_WATING:阻塞,被sleep这种固定时间的方式打断产生的阻塞

4.WATING:阻塞,被wait这种不固定时间的方式打断产生的阻塞

5.BLOCKED:阻塞,等待锁导致的阻塞,后续死锁讲解

6.TERMINATED:Thread对象还在,操作系统内核的线程结束了,也这样理解意味着该线程已经完成了其run方法的执行

public class test1 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("java");try {Thread.sleep(2000);} catch (InterruptedException e) {break;}}});System.out.println(t.getState());//只创建了Thread对象的NEW状态t.start();System.out.println(t.getState());//创建完线程t就是这个RUNNABLE状态Thread.sleep(1000);System.out.println(t.getState());//t线程处于睡眠t.interrupt();Thread.sleep(1000);System.out.println(t.getState());//t线程执行完了}
}

输出结果

后续线程出现卡死的情况,我们可以通过上述后面三种状态去确定卡死的原因是什么,最后两个状态后续再讲解

上述方法是多线程中非常常用的方法,要好好掌握,今天的内容就先到这,后面我们接着讲解线程还有不少的知识点等着💕

相关文章:

多线程(基础)

前言&#x1f440;~ 上一章我们介绍了什么是进程&#xff0c;对于进程就了解那么多即可&#xff0c;我们作为java程序员更关注线程&#xff0c;线程内容比较多&#xff0c;所以我们要分好几部分才能讲完 目录 进程的缺点 多线程&#xff08;重要&#xff09; 进程和线程的区…...

BUG cn.bing.com 重定向的次数过多,无法搜索内容

BUG cn.bing.com 重定向的次数过多&#xff0c;无法搜索内容 环境 windows 11 edge浏览器详情 使用Microsoft Edge 必应搜索显示"cn.bing.com"重定向次数过多&#xff0c;无法进行正常的检索功能 解决办法 检查是否开启某些科_学_上_网&#xff08;翻_墙&#xf…...

【数据科学】学习资源汇总(不定时更新)

好书推荐&#xff1a;BooksPDF/数据科学/Python数据科学手册.pdf at master zhixingchou/BooksPDF GitHub...

完美解决ValueError: column index (256) not an int in range(256)的正确解决方法,亲测有效!!!

完美解决ValueError: column index (256) not an int in range(256)的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 亲测有效 完美解决ValueError: column index (256) not an int in range(256)的正确解决方法&#xff0c;亲测有效&#xff01;&…...

# 音频处理4_傅里叶变换

1.离散傅里叶变换 对于离散时域信号 x[n]使用离散傅里叶变换&#xff08;Discrete Fourier Transform, DFT&#xff09;进行频域分析。 DFT 将离散信号 x[n] 变换为其频谱表示 X[k]&#xff0c;定义如下&#xff1a; X [ k ] ∑ n 0 N − 1 x [ n ] e − j 2 π k n N X[k]…...

提升网络速度的几种有效方法

在数字化时代&#xff0c;网络速度对于我们的日常生活和工作至关重要。无论是观看高清视频、在线游戏&#xff0c;还是进行视频会议&#xff0c;快速稳定的网络连接都是不可或缺的。如果你发现自己当前的网络速度不尽如人意&#xff0c;那么不妨尝试以下几种方法来提升它。 升…...

@PathVariable注解的使用及源码解析

前言 PathVariable 注解是我们进行JavaEE开发&#xff0c;最常见的几个注解之一&#xff0c;这篇博文我们以案例和源码相结合&#xff0c;帮助大家更好的了解PathVariable 注解 使用案例 1.获取 URL 上的值 RequestMapping("/id/{id}") public Object getId(Path…...

服务器配置重点看哪些参数

对服务器有需求时&#xff0c;应重点考虑以下几个关键参数&#xff0c;以下仅供参考&#xff1a; 处理器&#xff08;CPU&#xff09;&#xff1a;包括CPU的品牌&#xff08;如Intel或AMD&#xff09;、型号、核心数、线程数、主频和缓存大小。核心数越多&#xff0c;处理并发请…...

WSL Ubuntu 如何设置中文语言?

本章教程,主要介绍如何在WSL Ubuntu 如何设置中文语言。 操作系统:Windows 10 Pro 64 WSL子系统:Ubuntu 20.04 LTS 一、安装中文语言包 sudo apt install language-pack-zh-hans二、设置中文语言 sudo dpkg-reconfigure locales选择en_US.UTF-8 和 zh_CN.UTF-8 选择zh_CN.…...

「51媒体」政企活动媒体宣发如何做?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 政企活动媒体宣发是一个系统性的过程&#xff0c;需要明确…...

K近邻回归原理详解及Python代码示例

K近邻回归原理详解 K近邻回归&#xff08;K-Nearest Neighbors Regression, KNN&#xff09;是一种基于实例的学习算法&#xff0c;用于解决回归问题。它通过找到输入数据点在特征空间中最相似的K个邻居&#xff08;即最近的K个数据点&#xff09;&#xff0c;并使用这些邻居的…...

idea 开发工具properties文件中的中文不显示

用idea打开一个项目&#xff0c;配置文件propertise中的中文都不展示&#xff0c;如图&#xff1a; 可修改idea配置让中文显示&#xff1a; 勾选箭头指向的框即可&#xff0c;点击应用保存&#xff0c;重新打开配置文件&#xff0c;显示正常...

让DroidVNC-NG支持中文输入

DroidVNC-NG支持控制端输入内容&#xff0c;但是仅支持英文字符&#xff0c;如果需要控制输入法软键盘输入中文的话就没办法了&#xff0c;经过摸索找到了解决办法。 这个解决办法有个条件就是让DroidVNC-NG成为系统级应用&#xff08;这个条件比较苛刻&#xff09;&#xff…...

android dialog 显示时 activity 是否会执行 onPause onStop

当一个 Android Dialog 显示时&#xff0c;当前 Activity 通常不会执行 onPause 或 onStop 方法。Dialog 是附加到 Activity 上的一个窗口&#xff0c;它不会中断或替换当前的 Activity&#xff0c;因此 Activity 的生命周期方法 onPause 和 onStop 不会被调用。 然而&#xf…...

如何在MySQL中按字符串中的数字排序

在管理数据库时&#xff0c;我们经常遇到需要按嵌入在字符串中的数字进行排序的情况。这在实际应用中尤为常见&#xff0c;比如文件名、代码版本号等字段中通常包含数字&#xff0c;而这些数字往往是排序的关键。本文将详细介绍如何在MySQL中利用正则表达式提取字符串中的数字并…...

memcacheredis构建缓存服务器

Memcached&Redis构建缓存服务器 前言 许多Web应用都将数据保存到 RDBMS中&#xff0c;应用服务器从中读取数据并在浏览器中显示。但随着数据量的增大、访问的集中&#xff0c;就会出现RDBMS的负担加重、数据库响应恶化、 网站显示延迟等重大影响。Memcached/redis是高性能…...

Linux基础- 使用 Apache 服务部署静态网站

目录 零. 简介 一. linux安装Apache 二. 创建网页 三. window访问 修改了一下默认端口 到 8080 零. 简介 Apache 是世界使用排名第一的 Web 服务器软件。 它具有以下一些显著特点和优势&#xff1a; 开源免费&#xff1a;可以免费使用和修改&#xff0c;拥有庞大的社区支…...

接口自动化测试框架实战(Pytest+Allure+Excel)

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1. Allure 简介 Allure 框架是一个灵活的、轻量级的、支持多语言的测试报告工具&#xff0c;它不…...

如何预防和处理他人盗用IP地址?

IP地址的定义及作用 解释 IP 地址在互联网中的作用。它是唯一标识网络设备的数字地址&#xff0c;类似于物理世界中的邮政地址。 1、IP地址盗窃的定义 解释一下什么是IP地址盗用&#xff0c;即非法使用他人的IP地址或者伪造IP地址的行为&#xff0c;这种行为可能引发法律和安…...

【ai】李沐 动手深度学学v2 环境安装:anaconda3、pycharm、d2

cuda-toolkit cuda_12.5.0_windows_network.exe 官方课程网站 第二版资源下载release版本 pycharm版本 李沐 【动手学深度学习v2 PyTorch版】 课程笔记 CUDA 选择11, 实际下载 12.5.0...

前后端分离对软件行业及架构设计的影响

在软件开发领域&#xff0c;前后端分离是一种越来越流行的架构设计模式。这种方法将用户界面&#xff08;前端&#xff09;与服务器逻辑&#xff08;后端&#xff09;分离开来&#xff0c;允许它们独立开发、测试和部署。本文将探讨前后端分离对软件行业和架构设计的影响&#…...

深入解析Dubbo架构层次

什么是Dubbo&#xff1f; Dubbo是阿里巴巴开源的一款高性能优秀的服务框架&#xff0c;致力于提供高性能和透明化的 RPC 远程服务调用方案&#xff0c;以及 SOA 服务治理方案。它的主要功能包括&#xff1a; 远程通信&#xff1a;提供高效的远程通信能力。负载均衡&#xff1…...

关于GPIO的上拉、下拉,无上下拉

1.GPIO_PULLUP&#xff08;上拉&#xff09; 作用和原理 作用&#xff1a;上拉模式会在GPIO引脚和电源电压&#xff08;Vcc&#xff09;之间连接一个内部上拉电阻。原理&#xff1a;当引脚配置为输入模式时&#xff0c;如果引脚没有连接到其他外部电路&#xff0c;内部上拉电…...

Python 语法基础二

7.常用内置函数 执行这个命令可以查看所有内置函数和内置对象&#xff08;两个下划线&#xff09; >>>dir(__builtins__) [__class__, __contains__, __delattr__, __delitem__, __dir__, __doc__, __eq__, __format__, __ge__, __getattribute__, __getitem__, __gt…...

HTML5与HTML:不仅仅是标签的革新

当我们提到HTML5&#xff0c;很多人会想到这是HTML的一个升级版本&#xff0c;增加了许多新的标签和特性。然而&#xff0c;HTML5带来的变化远不止于此。它是一个全面的网页开发框架&#xff0c;重新定义了网络应用程序的构建方式&#xff0c;为开发者提供了前所未有的灵活性和…...

Mybatis面试学习

1.介绍一下mybatis mybatis是一个半自动的ORM的框架&#xff0c;ORM就是对象关系映射。&#xff08;对象指的是Java对象&#xff0c;关系指的是数据库中的关系模型&#xff0c;对象关系映射&#xff0c;指的就是在Java对象和数据库的关系模型之间建立一种对应关系&#xff09;…...

el-date-picker设置时间范围

下面这种写法会报错&#xff1a;找不到expirationDate&#xff0c;这是因为涉及到this的指向问题 在普通函数中&#xff0c;this 的上下文并不指向 Vue 组件实例&#xff0c;而是取决于函数的调用方式或者是否使用了严格模式 <el-date-pickerclass"date-icon-common&q…...

Links: Challenging Puzzle Game Template(益智游戏模板)

链接:挑战益智游戏 《Links》是一款独特且具有挑战性的益智游戏,即将发布。 每个级别都会向玩家展示不同的棋盘。目标是通过移动和旋转所有棋子来连接它们。每个棋子都有自己的特点和功能-你可以移动它们,旋转它们,或者两者兼而有之。连接所有棋子,以解决难度和挑战不断增…...

java基于ssm+jsp 仓库智能仓储系统

1管理员功能模块 管理员登录&#xff0c;通过填写用户名、密码等信息&#xff0c;输入完成后选择登录即可进入智能仓储系统 &#xff0c;如图1所示。 图1管理员登录界面图 智能仓储系统 &#xff0c;在智能仓储系统可以查看个人中心、公告信息管理、员工管理、供应商管理、商…...

第24篇 滑动开关控制LED<二>

Q&#xff1a;如何使用Intel FPGA Monitor Program创建滑动开关控制LED工程并运行呢&#xff1f; A&#xff1a;创建工程的基本过程与前面的Intel FPGA Monitor Program的使用<三>一样&#xff0c;不同的地方是&#xff0c;本实验工程用到了开发板的外设硬件LED和SW&…...

Redis单例部署

目录 1. 概述2. 参考3. 环境4. 部署4.1 操作系统4.1.1 修改系统参数4.1.2 关闭透明大页内存4.1.3 修改系统限制 4.2 安装Redis4.2.1 下载Redis4.2.2 创建redis账号4.2.3 添加Redis环境变量4.2.4 创建Redis使用目录4.2.5 安装Redis4.2.6 手动修改配置文件&#xff08;**可跳过&a…...

HarmonyOS4升级到Harmonyos Next(Api 11)学习捷径

HarmonyOS4升级到Harmonyos Next&#xff08;Api 11&#xff09;学习捷径&#xff0c;新技术学习路上少走弯路。HarmonyOS NEXT和HarmonyOS 4的基本语法都是一样的&#xff0c;但是还有一些区别。如果你学会HarmonyOS4&#xff0c;那么HarmonyOS Next也自然而然的会了。 Harmon…...

[电子电路学]电路分析基本概念1

第一章 电路分析的基本概念和基本定律 电路模型 反映实际电路部件的主要电磁性质的理想电路元件及其组合&#xff0c;是实际电路电气特性的抽象和近似。 理想电路元件 实际电路器件品种繁多&#xff0c;其电磁特性多元而复杂&#xff0c;分析和计算时非常困难。而理想电路元件…...

Linux bash: /usr/local/gcc/bin/gcc: 不是目录

ln -s /usr/local/bin/gcc /usr/bin/gcc ln -s /usr/local/bin/g /usr/bin/g 创建的软连接不生效 问题&#xff1a; [rootdev003 local]# gcc -v bash: /usr/local/gcc/bin/gcc: 不是目录 或者 [rootdev003 local]# gcc -v bash: /usr/local/bin/gcc: 没有那个文件或目录 解决&…...

vue项目中,pnpm不能用-解决

方法四&#xff1a;解决 PowerShell 执行策略问题 如果你决定继续使用 PowerShell&#xff0c;并且遇到执行策略问题&#xff0c;可以尝试以下方法解决&#xff1a; 永久更改执行策略&#xff1a; 在管理员权限的 PowerShell 中运行以下命令&#xff0c;以永久更改执行策略&am…...

数据处理python

1.列筛选 &#xff08;1&#xff09;某一列&某几列 对于一个表单里面的数据&#xff0c;如果我们想要对于这个表单里面的数据进行处理&#xff0c;我们可以一列一列进行处理&#xff0c;也可以多列一起进行处理&#xff1b; 一列一列处理&#xff1a; 只需要在这个dataf…...

【MotionCap】SLAHMR 在 Colab 的demo运行笔记

【MotionCap】SLAHMR slahmr将人类和相机运动与野外视频分离 CVPR 2023跳至主要内容 SLAHMR (supports 4D Humans).ipynb SLAHMR (supports 4D Humans).ipynb_笔记本已移除星标Google Colab demo for: SLAHMR - Simultaneous Localization And Human Mesh Recovery @inproc…...

Qt-Advanced-Docking-System示例程序

写了一些简单的示例程序&#xff0c;帮助我更好地使用和了解Qt-Advanced-Docking-System 1.写一个如图页面布局的程序 m_pDockMangernew ads::CDockManager(this);this->setCentralWidget(m_pDockManger);ads::CDockWidget* centerDockWidgetnew ads::CDockWidget("中…...

戴尔笔记本重装系统?笔记本卡顿失灵?一键重装系统!

随着科技的快速发展&#xff0c;笔记本电脑已成为我们日常生活和工作中不可或缺的工具。然而&#xff0c;随着时间的推移&#xff0c;笔记本可能会遇到各种问题&#xff0c;如系统卡顿、失灵等。这时&#xff0c;重装系统往往是一个有效的解决方案。本文将详细介绍如何在戴尔笔…...

ViewController 的常用跳转及返回方法

ViewController 的常用跳转及返回方法 ViewController 的常用跳转及返回方法模态跳转导航控制器选项卡控制器Storyboard 的 segues 方式跳转 ViewController 的常用跳转及返回方法 模态跳转 一个普通的视图控制器一般只有模态跳转的功能&#xff0c;这个方法是所有视图控制器…...

FFmpeg开发笔记(四十一)结合OBS与MediaMTX实现SRT直播推流

《FFmpeg开发实战&#xff1a;从零基础到短视频上线》一书的“10.2 FFmpeg推流和拉流”提到直播行业存在RTSP和RTMP两种常见的流媒体协议。除此以外&#xff0c;还有于2017年推出的SRT协议&#xff0c;相比常见的RTMP协议&#xff0c;SRT协议具有更低的延迟&#xff0c;并且消…...

探索AI的巅峰:详解GPT-3.5与GPT-4系列模型的区别

人工智能领域不断涌现出令人惊叹的技术突破&#xff0c;其中OpenAI的ChatGPT系列模型尤为引人注目。随着GPT-4的发布&#xff0c;技术开发者们对比分析其与前一代GPT-3.5的差异显得尤为重要。本文将深入探讨GPT-3.5和GPT-4系列模型的主要区别&#xff0c;帮助大家更好地理解和应…...

Linux-笔记 使用SCP命令传输文件报错 :IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!

前言 使用scp命令向开发板传输文件发生报错&#xff0c;报错见下图; 解决 rm -rf /home/<用户名>/.ssh/known_hosts 此方法同样适用于使用ssh命令连接开发板报错的情况。 参考 https://blog.csdn.net/westsource/article/details/6636096...

计算机网络 静态路由及动态路由RIP

一、理论知识 1.静态路由 静态路由是由网络管理员手动配置在路由器上的固定路由路径。其优点是简单和对网络拓扑变化不敏感&#xff0c;缺点是维护复杂、易出错&#xff0c;且无法自动适应网络变化。 2.动态路由协议RIP RIP是一种基于距离向量的动态路由协议。它使用跳数作…...

Django实现部门管理功能

在这篇文章中,我们将介绍如何使用Django框架实现一个简单的部门管理功能。这个功能包括部门列表展示、添加新部门、编辑和删除部门等操作。 1. 项目设置 首先,确保你已经安装了Django并创建了一个新的Django项目。在项目中,我们需要创建一个名为​​app01​​的应用。 2.…...

概率论与数理统计期末复习

概率论常考知识点汇总 总括 1. 基础概率论 概率定义&#xff1a;理解概率是事件发生的可能性度量&#xff0c;范围从0&#xff08;不可能&#xff09;到1&#xff08;必然发生&#xff09;。概率公理&#xff1a;掌握概率的三大公理&#xff0c;即非负性、规范性和可加性。条…...

python 识别图片点击,设置坐标,离设置坐标越近的优先识别点击

import pyautogui import cv2 import numpy as np import mathdef find_and_click(template_path, target_x, target_y, match_threshold0.8):"""在屏幕上查找目标图片并点击。Args:template_path: 目标图片的路径。target_x: 预设的坐标 x 轴值。target_y: 预设…...

【实战教程】如何使用JMeter来轻松测试WebSocket接口?

1、websocket接口原理 打开网页&#xff1a;从http协议&#xff0c;升级到websocket协议&#xff0c;请求建立websocket连接服务器返回建立成功成功客户端向服务端发送匹配请求服务端选择一个客服上线服务器返回客服id客户端向服务器发送消息服务器推送消息给指定的客服服务器…...

【linux】详解——库

目录 概述 库 库函数 静态库 动态库 制作动静态库 使用动静态库 如何让系统默认找到第三方库 lib和lib64的区别 /和/usr/和/usr/local下lib和lib64的区别 环境变量 配置相关文件 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 简介&#xff1a;C站最萌博主 相关…...

RuntimeError: “exp_vml_cpu“ not implemented for ‘Half‘

遇到 "exp_vml_cpu" not implemented for Half 这个运行时错误&#xff0c;意味着你尝试在一个操作中使用了半精度&#xff08;Half 或 float16&#xff09;数据类型&#xff0c;但是该操作在当前环境下并没有针对半精度数据类型的实现。 半精度&#xff08;float16&…...