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

3. 多线程(1) --- 创建线程,Thread类

文章目录

  • 前言
  • 1. API
  • 2. 创建线程
    • 2.1. 继承 Thread类
    • 2.2. 实现 Runnable 接口
    • 2.3. 匿名内部类
    • 2.4. lambda
    • 2.5.其他方法
  • 3. Thread类及其常见的方法和属性
    • 3.1. Thread 的常见构造方法
    • 3.2. Thread 的常见属性
    • 3.3. start() --- 启动一个线程
    • 3.4. 中断一个线程
    • 3.5. 等待线程
    • 3.6. 休眠当前线程


前言

上一节课,我们主要引出了线程,以及线程和进程的联系与区别,从这篇博客开始,我们开始编写代码了,Let’s go!


1. API

线程是操作系统提供的概念,操作系统系统提供一些API供程序员使用。什么是 API 呢?
API (Aoolication Programming Interface) 应用程序编程接口,简单来说,就是别人写了一些类 / 函数,可以直接拿过来使用。
来源:api 的来源很广泛,例如 标准库,第三方库,其他的各种开源项目,甚至是在工作中,隔壁项目给你提供的代码。
并且呀,操作系统提供的原生线程 api 是 C语言的,并且不同的操作系统的线程 api 是不一样的。
为此, Java 对上述内容统一封装,提供Thread (标准库中的类)


2. 创建线程

2.1. 继承 Thread类

class MyThread extends Thread{@Overridepublic void run() {while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("Hello thread!");}}
}
public class Demo1 {public static void main(String[] args) throws InterruptedException {// 方法一:创建一个 MyThread 类继承 Thread,重写 run 方法Thread thread = new MyThread();thread.start();while (true){System.out.println("Hello main");Thread.sleep(1000);}}
}

上面便是创建一个 MyThread 类 继承 Thread,重写run方法的形式,下面我们来分别说一下。

class MyThread extends Thread{@Overridepublic void run() {while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("Hello thread!");}}
}

这段代码中,是我们自己利用JVM自带的Thread类实现的一个MyThread,并且重写了run方法,当我们调用线程的时候,就直接运行run方法的内容了,无需调用。
为什么不需要调用 run()方法呢?
因为 run() 相当于 回调函数
例如在Java的数据结构中,优先级队列执行比较规则,如果使用 Comparator 接口,方式就是 compare,如果使用 Comparable接口,方法就是 compareTo,我们没有调用这个函数,他就自己就调用了,这就是回调函数

Thread.sleep(1000);

这个方法是Thread 的静态方法,参数是毫秒,效果就是,当前的线程放弃 CPU 资源,休息一会,时间过了,再执行。为什么要进行这个操作呢,因为如果不休眠的话,那么 这两个线程会一直吃 CPU 的资源,可能会造成 电脑的卡顿,并且让 线程休息一下,也便于我们观察现象。
这个方法会抛出 InterruptedException 异常,需要我们 使用 try catch 进行捕获。因为 run()方法没有 throws ,所以就不能向上抛出异常,只能使用 try catch,这个跟下面的main方法中的不太一样。

Thread thread = new MyThread();

这个就创建了一个线程 thread,和main 线程一起执行。

thread.start();

thread 线程 开始执行,此处为什么不调用 thread.run(),而是 thread.start()

 		while (true){System.out.println("Hello main");Thread.sleep(1000);}

这段代码是main线程中执行的逻辑,跟上面 thread 几乎一模一样,就是为了观察效果的。
在这里插入图片描述
效果显而易见,我们发现 Hello main 和 Hello thread!,运行的过程中,是轮番打印的,并且没有规律。
在这说一下如果调用的是 thread.run()而不是 thread.start(),会出现什么现象。

public class Demo01 {public static void main(String[] args) throws InterruptedException {// 方法一:创建一个 MyThread 类继承 Thread,重写 run 方法Thread thread = new MyThread();//thread.start();thread.run();while (true){System.out.println("Hello main");Thread.sleep(1000);}}
}

运行情况:
在这里插入图片描述
相当于thread线程就没有运行,因此不要这样写代码。

2.2. 实现 Runnable 接口

class MyRunnable implements Runnable{@Overridepublic void run() {while (true){try {System.out.println("Hello thread!");Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class Demo02 {public static void main(String[] args) throws InterruptedException {Runnable runnable = new MyRunnable();Thread thread = new Thread(runnable);thread.start();while (true){System.out.println("Hello main!");Thread.sleep(1000);}}
}
Runnable runnable = new MyRunnable();

这个就是一个任务,一段要执行的逻辑,最终还是要通过 Thread ,才能创建真正的线程,那为什么这样子写呢?或者就是这样子写有什么好处?
可以做到解耦合
意思就是,让要执行任务本身这个事情,和 线程这个事可以 关联没有那么大,从而后续如果要变更代码 (比如不通过线程执行这个任务,而是通过其他方法…),那么采用 Runnable 这样的方案,代码的修改就会更简单了。
与此相关的还有一个名词高内聚
例如,写了一个项目,有很多代码,有很多文件,也有很多类,以及很多的逻辑,其中把有关联的各种代码,放到一起,只要把某个功能逻辑相关的东西,都放到一起,那么就称之为高内聚
反之,如果是某个功能的代码,东一块,西一块的,那么就是低内聚
因此么,我们在写代码的时候,通常要做到高内聚,低耦合
现象跟上面的情况差不多。
在这里插入图片描述

2.3. 匿名内部类

利用 Thread 来使用 匿名内部类

public class Demo03 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(){@Overridepublic void run() {while (true){System.out.println("Hello thread!");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};thread.start();while (true){System.out.println("Hello main!");Thread.sleep(1000);}}
}
Thread thread = new Thread(){};

这个代码做了三个事情:

  1. 创建了一个 Thread 的子类,子类叫什么名字?不知道,他是个匿名!
  2. { } 里面就可以编写子类的定义代码,子类里有哪些属性,要有哪些方法,重写父类哪些方法…都可以往里面写。
  3. 创建了这个匿名内部类的实例,并且把实例的引用赋值给了 t。

同理,下面 Runnable 也是这个意思。
现象如下图所示:

在这里插入图片描述

利用 Runnable 来实现 匿名内部类

public class Demo04 {public static void main(String[] args) throws InterruptedException {Runnable runnable = new Runnable() {@Overridepublic void run() {while (true){System.out.println("Hello Thread!");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};Thread thread = new Thread(runnable);thread.start();while (true){System.out.println("Hello main!");Thread.sleep(1000);}}

在这里插入图片描述
使用匿名内部类的好处就是:
少定义一些类。
一般如果某个代码是 “一次性的”,就可以使用匿名内部类的写法。

2.4. lambda

其实 lambda 表达式的本质,就是回调函数,使用 () -> {}

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

注意。没有 Runnable 的形式。
咱们上课主要就是使用 lambda 表达式的形式来创建线程。

2.5.其他方法

不止上面的四种方法,还有两种,一个是线程池,另外一种是实现Callable接口,等到后面我们再说。


3. Thread类及其常见的方法和属性

3.1. Thread 的常见构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target,String name)使用 Runnable 对象创建线程对象,并命名
【了解】Thread(ThreadGroup group,Runnable target)线程可以被用来分组管理,分好的组即为线程组,这个目前了解即可

其中第一个和第二种方法,都已经演示过了,直接演示第四个吧。

public class Demo06 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{while (true){System.out.println("Hello t1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}},"t1");Thread t2 = new Thread(()->{while (true){System.out.println("Hello t2");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}},"t2");t1.start();t2.start();while (true){System.out.println("Hello main");Thread.sleep(1000);}}
}

此时,我们打开JDK自带的软件 jconsole (在JDK的bin目录下面),
在这里插入图片描述
其中,没有用红色框起来的都是JVM自带的线程,跟咱们没有关系。
其中t1,t2都是我们定义好的线程名称,如果没有定义名字的话,会是什么样子的呢?
在这里插入图片描述
是这个样子的。

3.2. Thread 的常见属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  • ID 是线程的唯一标识,不同线程不会重复
  • 名称是各种调试工具用到的
  • 状态表示线程当前所处的一个情况,下面我们会进一步说明
  • 优先级高的线程理论上来说更容易被调度到
  • 关于后台线程,需要记住:JVM会在一个进程的所有非后台线程结束后,才会结束运行
  • 是否存活,一个简单的理解,就是run方法是否运行结束了
  • 线程中断问题,下面我们再说。

在这又得解释一些名词,并且再加上一些代码。
第一个如果获取到线程的名字。
使用这个类中的函数 Thread.currentThread().getName()

public class Demo07 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{while (true) {System.out.println("hello " + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t1.start();while (true){System.out.println("hello main");Thread.sleep(1000);}}
}

第二个什么是isDaemon()?
表格上写的是后台线程,但是如果按照英语翻译的话是 守护线程。翻译成守护线程,但是要把他理解成后台线程。怎么理解呢?
具体例子:中秋节亲戚们聚餐吃饭,等到一家子人,全部坐齐,举杯碰一个之后,然后开始吃饭,但是么,我下午还有课,我就哐哐地吃饭,我吃饱喝足要去上课了,剩余的亲戚都没有吃完呢,但是我就要出门了。
在上述的过程中,把房间看成程序,把自己一个人闷头吃饭看做一个线程(t1),把剩余的人一起吃完饭,看成另一个线程(t2),对于t1来说,不管t2是否完成,t1一结束,那么程序必须关闭,那么此时就把t2设置为后台线程,也就是说,不管大家吃完了没有(t2是否结束),我吃完饭,房间门必须要打开(程序就要结束了),我就要走了。

public static void main(String[] args) {Thread t1 = new Thread(()->{while (true){System.out.println("全家人一直在吃");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t2 = new Thread(()->{for (int i = 0;i<3;i++){System.out.println("我也在吃,但是吃完饭就要结束这个线程");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t1.setDaemon(true);t1.start();t2.start();}

结果:
在这里插入图片描述

如果没有setDemon(true),那会发生什么呢?

public static void main(String[] args) {Thread t1 = new Thread(()->{while (true){System.out.println("全家人一直在吃");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t2 = new Thread(()->{for (int i = 0;i<3;i++){System.out.println("我也在吃,但是吃完饭就要结束这个线程");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});//t1.setDaemon(true);t1.start();t2.start();}

在这里插入图片描述
如果按照第二种的话,意思就是说,我都已经吃饱喝足了,我还是不走,线程 t2 还要在程序中等待。
获得 线程的名字 在上面的代码已经使用过了,在这都不写了。

3.3. start() — 启动一个线程

 public static void main(String[] args) {Thread t = new Thread(() -> {System.out.println("hello thread");});t.start();}

这个是个很简单的代码,大家应该都可以看懂,如果我们这样写代码,看看会出现什么情况

 public static void main(String[] args) {Thread t = new Thread(() -> {System.out.println("hello thread");});t.start();t.start();}

在这里插入图片描述
由此我们可以看出,线程不能重复start。
通过我们查看 线程 start的。
在这里插入图片描述

3.4. 中断一个线程

我们使用两种方式来中断线程,方案一:使用变量 isFinished,方案二:使用interrupt方法。
方案一:使用变量 isFinished。

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

上面代码意思:t线程每隔1秒,打印一个 “Hello Thread!”,3秒以后,不再打印。
这个是通过 isFinished 变量来确定的。在这提一个问题:

public static boolean isFinshed = false;

这个代码可不可以写在main函数里面?
答案是不行的。

public class Demo10 {//public static boolean isFinshed = false;public static void main(String[] args) throws InterruptedException {boolean isFinshed = false;Thread t = new Thread(() -> {while (!isFinshed){System.out.println("Hello Thread!");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();Thread.sleep(3000);isFinshed = true;}
}

在这里插入图片描述
为什么呢?

在第二种写法中(isFinished变量在main方法中),触发了变量捕获
lambda是回调函数,执行时机,是很久以后才会被执行的(操作系统真正创建出线程之后),很有可能,后续线程都创建好了,当前main这里的方法都执行完了,对应的isFinished 都已经销毁了,为了解决这个问题,Java的做法是,把被捕获的变量拷贝一份,拷贝到 lambda im,外面的变量是否销毁,并不影响 lambda方面里面的变量。
但是还是没有解决问题,拷贝,意味着,这样的变量就不适合进行修改,修改一方,另外一方不会随之变化,本质上是两个变量,这种一边变化,一边又不变,可能会给程序员带来更多的疑惑,那么Java大佬直接压根就不让这个变量进行修改,这就是变量捕获操作。

那么为什么第一种都可以了?
因为第一种写法把 isFinished 这个变量改写成 成员变量,此时就不再是 “变量捕获” 语法,
而是切换成 **“内部类访问外部类的成员”**语法。
lambda 本质上是 函数式接口,相当于一个内部类,isFinished 变量本身是外部类的成员,内部类本来就能够访问外部类的成员。并且 成员变量的生命周期,也是让 GC (垃圾回收)管理的,在 lambda 里面不担心变量生命周期失效的问题,那么就不必拷贝,也就不必限制 final 之类。

下面我们使用 Interrupt 方法来终止线程。

public class Demo11 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {while (!Thread.currentThread().isInterrupted()){System.out.println("Hello Thread!");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("t 线程 结束");});t.start();Thread.sleep(3000);System.out.println("main 线程 尝试 阻塞 t 线程");t.interrupt();}
}

结果:
在这里插入图片描述
其中:
Thread.currentThread().isInterrupted()判断线程时候被终止了 (其实是判断 Thread 里的 boolean 变量的值)
t.interrput()主动去进行终止的 (修改这个 Boolean 变量的值)
当然,除了设置Boolean 变量 (标志位) 之外,还能够唤醒 像 sleep 这样的阻塞方法。
如果我们把 throw new RuntimeException(e);
这个代码给注释掉,看看会发生什么情况。

public class Demo11 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {while (!Thread.currentThread().isInterrupted()){System.out.println("Hello Thread!");try {Thread.sleep(1000);} catch (InterruptedException e) {//throw new RuntimeException(e);break;}}System.out.println("t 线程 结束");});t.start();Thread.sleep(3000);System.out.println("main 线程 尝试 阻塞 t 线程");t.interrupt();}
}

结果:在这里插入图片描述
发生上面的代码的原因,是 sleep 捣鬼。
正常来说,调用 interrput 方法就会修改 isInterrputted 方法内部的标志位 设置为 true
由于上述代码,是把 sleep 给 唤醒了
这种唤醒的情况下,sleep 就会在唤醒 之后,把 isInterruptted 标志位 设置为 false
因此在这样的情况下,如果继续执行到循环的条件判定,就会能够继续执行。

3.5. 等待线程

多个线程之间 是并发执行的,也是随机调度的。
站在 程序员的角度来说,咱们不喜欢随机的东西的。
join 能够要求,多个线程之间结束的 先后顺序
sleep 可以通过 休眠的时间,来控制线程结束的顺序的,但是有的时候,这样的设定是并不科学的。
有的时候,希望 t 先 结束,main 就可以紧跟着结束,此时通过设置时间的方式,不一定靠谱。

public class Demo12 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{for (int i = 0;i<3;i++){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("t 线程结束");});t.start();t.join();System.out.println("main 线程结束");}
}

结果:
在这里插入图片描述
此时上面代码的逻辑就是,t每休息1s,打印一次 hello thread,执行三次,main一直等待。

join 也提供了带有时间参数的版本。意思就是等待的最多时间

public class Demo12 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{for (int i = 0;i<5;i++){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("t 线程结束");});t.start();t.join(3000);System.out.println("main 线程结束");}
}

在这里插入图片描述
此时,t.joiin(3000)意思就是:如果在 30000ms之内,t 线程结束了,那么此时 join 立即继续执行 (不会等满 3000ms),如果超过3000ms,t线程还没结束,那么此时 join() 往下执行,就不等 t 线程了。
这种带有超时时间版本的等待,才是是更加科学的做法。计算机中,尤其是和网络通信相关的逻辑,一般都是需要超时时间的#

3.6. 休眠当前线程

这个sleep方法我们之前一直在用,在这我们就不展开细讲了
在这里插入图片描述


下节课,我们就要讲述线程的状态和线程不安全的情况了,我们不见不散。

相关文章:

3. 多线程(1) --- 创建线程,Thread类

文章目录 前言1. API2. 创建线程2.1. 继承 Thread类2.2. 实现 Runnable 接口2.3. 匿名内部类2.4. lambda2.5.其他方法 3. Thread类及其常见的方法和属性3.1. Thread 的常见构造方法3.2. Thread 的常见属性3.3. start() --- 启动一个线程3.4. 中断一个线程3.5. 等待线程3.6. 休眠…...

简单的jmeter数据请求学习

简单的jmeter数据请求学习 1.需求 我们的流程服务由原来的workflow-server调用wfms进行了优化&#xff0c;将wfms服务操作并入了workflow-server中&#xff0c;去除了原来的webservice服务调用形式&#xff0c;增加了并发处理&#xff0c;现在想测试模拟一下&#xff0c;在一…...

智能水文:ChatGPT等大语言模型如何提升水资源分析和模型优化的效率

大语言模型与水文水资源领域的融合具有多种具体应用&#xff0c;以下是一些主要的应用实例&#xff1a; 1、时间序列水文数据自动化处理及机器学习模型&#xff1a; ●自动分析流量或降雨量的异常值 ●参数估计&#xff0c;例如PIII型曲线的参数 ●自动分析降雨频率及重现期 ●…...

民宿酒店预订系统小程序+uniapp全开源+搭建教程

一.介绍 一.系统介绍 基于ThinkPHPuniappuView开发的多门店民宿酒店预订管理系统&#xff0c;快速部署属于自己民宿酒店的预订小程序&#xff0c;包含预订、退房、WIFI连接、吐槽、周边信息等功能。提供全部无加密源代码&#xff0c;支持私有化部署。 二.搭建环境 系统环境…...

计算机网络掩码、最小地址、最大地址计算、IP地址个数

一、必备知识 1.无分类地址IPV4地址网络前缀主机号 2.每个IPV4地址由32位二进制数组成 3. /15这个地址表示网络前缀有15位&#xff0c;那么主机号32-1517位。 4.IP地址的个数&#xff1a;2**n (n表示主机号的位数) 5.可用&#xff08;可分配&#xff09;IP地址个数&#x…...

Mac中配置vscode(第一期:python开发)

1、终端中安装 xcode-select --install #mac的终端中安装该开发工具 xcode-select -p #显示当前 Xcode 命令行工具的安装路径注意&#xff1a;xcode-select --install是在 macOS 上安装命令行开发工具(Command Line Tools)的关键命令。安装的主要组件包括&#xff1a;C/C 编…...

软件项目体系建设文档,项目开发实施运维,审计,安全体系建设,验收交付,售前资料(word原件)

软件系统实施标准化流程设计至关重要&#xff0c;因为它能确保开发、测试、部署及维护等各阶段高效有序进行。标准化流程能减少人为错误&#xff0c;提升代码质量和系统稳定性。同时&#xff0c;它促进了团队成员间的沟通与协作&#xff0c;确保项目按时交付。此外&#xff0c;…...

计算机网络--路由表的更新

一、方法 【计算机网络习题-RIP路由表更新-哔哩哔哩】 二、举个例子 例1 例2...

CDN防御如何保护我们的网络安全?

在当今数字化时代&#xff0c;网络安全成为了一个至关重要的议题。随着网络攻击的日益频繁和复杂化&#xff0c;企业和个人都面临着前所未有的安全威胁。内容分发网络&#xff08;CDN&#xff09;作为一种分布式网络架构&#xff0c;不仅能够提高网站的访问速度和用户体验&…...

matlab离线安装硬件支持包

MATLAB 硬件支持包离线安装 本文章提供matlab硬件支持包离线安装教程&#xff0c;因为我的matlab安装的某种原因&#xff08;破解&#xff09;&#xff0c;不支持硬件支持包的安装&#xff0c;相信也有很多相同情况的朋友&#xff0c;所以记录一下我是如何离线安装的&#xff…...

使用virtualenv创建虚拟环境

下载 virtualenv pip install virtualenv 创建虚拟环境 先进入想要的目录 一般为 /envs virtualenv 文件名 --python解释器的版本 激活虚拟环境 .\虚拟项目的文件夹名称\Scripts\activate 退出虚拟环境 deactivate...

Java链表

链表(Linked List)是一种线性数据结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含两部分&#xff1a;一部分为用于储存数据元素&#xff0c;另部分是一种引用(指针),指向下一个节点。 这种结构允许动态地添加和删除元素&#xff0c;而不需要像数组那种大规模的数…...

Zero to JupyterHub with Kubernetes 下篇 - Jupyterhub on k8s

前言&#xff1a;纯个人记录使用。 搭建 Zero to JupyterHub with Kubernetes 上篇 - Kubernetes 离线二进制部署。搭建 Zero to JupyterHub with Kubernetes 中篇 - Kubernetes 常规使用记录。搭建 Zero to JupyterHub with Kubernetes 下篇 - Jupyterhub on k8s。 官方文档…...

解决 Tomcat 跨域问题 - Tomcat 配置静态文件和 Java Web 服务(Spring MVC Springboot)同时允许跨域

解决 Tomcat 跨域问题 - Tomcat 配置静态文件和 Java Web 服务&#xff08;Spring MVC Springboot&#xff09;同时允许跨域 Tomcat 配置允许跨域Web 项目配置允许跨域Tomcat 同时允许静态文件和 Web 服务跨域 偶尔遇到一个 Tomcat 部署项目跨域问题&#xff0c;因为已经处理…...

在C语言中使用伪终端与bash交互

了解伪终端概念&#xff1a; 伪终端&#xff08;PTY&#xff09;由一对设备组成&#xff1a;主设备&#xff08;master&#xff09;和从设备&#xff08;slave&#xff09;。数据写入主设备会出现在从设备&#xff0c;反之亦然。这允许一个进程通过主设备与另一个进程&#xff…...

阿里云 人工智能与机器学习

阿里云的 人工智能&#xff08;AI&#xff09;与机器学习&#xff08;ML&#xff09; 服务为企业提供了全面的AI解决方案&#xff0c;帮助用户在多个行业实现数据智能化&#xff0c;提升决策效率&#xff0c;推动业务创新。阿里云通过先进的技术和丰富的工具&#xff0c;支持用…...

HTML 显示器纯色亮点检测工具

HTML 显示器纯色亮点检测工具 相关资源文件已经打包成html等文件&#xff0c;可双击直接运行程序&#xff0c;且文章末尾已附上相关源码&#xff0c;以供大家学习交流&#xff0c;博主主页还有更多Html相关程序案例&#xff0c;秉着开源精神的想法&#xff0c;望大家喜欢&#…...

【漏洞分析】UDF提权漏洞——CVE-2016-6662-MySQL ‘malloc_lib’变量重写命令执行

0x00 前言 最近在做渗透笔记&#xff0c;其中有一个靶机在getshell后&#xff0c;需要进行提权。发现靶机使用root启动的mysql服务&#xff0c;那么尝试使用UDF提权。于是在提权成功后&#xff0c;花了一天时间特意搜了一下整个UDF提权的漏洞原理和利用&#xff0c;加深理解。…...

Mybatis(day09)

Mybatis基础操作 功能列表&#xff1a; 查询 根据主键ID查询 条件查询新增更新删除 根据主键ID删除 根据主键ID批量删除 准备 实施前的准备工作&#xff1a; 准备数据库表创建一个新的 springboot 工程&#xff0c;选择引入对应的起步依赖&#xff08;mybatis、mysql 驱动、…...

模式识别与机器学习 | 十一章 概率图模型基础

隐马尔科夫模型&#xff08;Hidden Markov Model,HMM&#xff09; HMM是建模序列数据的图模型 1、第一个状态节点对应一个初始状态概率分布 2、状态转移矩阵A, 3、发射矩阵概率B 4、对特定的&#xff08;x,y&#xff09;的联合概率可以表示为 α递归计算——前向算法β递归…...

SpringSecurity+vue通用权限系统

SpringSecurityvue通用权限系统 采用主流的技术栈实现&#xff0c;Mysql数据库&#xff0c;SpringBoot2Mybatis Plus后端&#xff0c;redis缓存&#xff0c;安全框架 SpringSecurity &#xff0c;Vue3.2Element Plus实现后台管理。基于JWT技术实现前后端分离。项目开发同时采 …...

uni-app学习笔记三十--request网络请求传参

request用于发起网络请求。 OBJECT 参数说明 参数名类型必填默认值说明平台差异说明urlString是开发者服务器接口地址dataObject/String/ArrayBuffer否请求的参数App 3.3.7 以下不支持 ArrayBuffer 类型headerObject否设置请求的 header&#xff0c;header 中不能设置 Refere…...

如何安装并使用RustDesk

参考&#xff1a; 搭建 RustDesk Server&#xff1a;打造属于自己的远程控制系统&#xff0c;替代 TeamViewer 和 ToDesk&#xff01; 向日葵、ToDesk再见&#xff01;自己动手&#xff0c;自建RustDesk远程服务器真香&#xff01; 通俗易懂&#xff1a;RustDesk Server的搭…...

vmware 设置 dns

vmware 设置 dns 常用的 DNS&#xff08;Domain Name System&#xff09;服务器地址可以帮助你更快、更安全地解析域名。以下是一些国内外常用的公共 DNS 服务&#xff1a; 国内常用 DNS 阿里云 DNS IPv4: 223.5.5.5、223.6.6.6IPv6: 2400:3200::1、2400:3200:baba::1特点&am…...

感谢阿里云RDS产品及时的“光速服务”

❝ 开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, OceanBase, Sql Server等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;&#xff08;共3000人左右…...

机器学习方法实现数独矩阵识别器

目录 导包 工具函数构建说明 1. 基础图像处理工具 2. 图像预处理模块 3. 数独轮廓检测与定位 4. 网格划分与单元格提取 5. 数字特征提取 6. 多网格处理流程 数据流分析 核心算法详解 核心机器视觉方法 1. 透视变换校正算法 2. 数字区域提取算法 3. 多网格检测算法…...

F(x,y)= 0 隐函数 微分法

&#x1f7e6; 一、隐函数微分法简介 ▶ 什么是隐函数&#xff1f; 显函数&#xff1a;形如 y f ( x ) y f(x) yf(x)&#xff0c;变量之间是显式关系。 隐函数&#xff1a;形如 F ( x , y ) 0 F(x, y) 0 F(x,y)0&#xff0c;变量间不是直接表达的&#xff0c;需要通过…...

AI是如何换装的?

AI换装是一种基于计算机视觉、深度学习和生成对抗网络(GAN)的技术,能够通过算法自动识别人像并更换服饰,实现虚拟换装的效果。这项技术广泛应用于电商服装试穿、虚拟偶像、影视特效、社交媒体滤镜等领域。 AI换装的核心技术 1. 图像分割与人体解析 换装的第一步是图像分…...

微软重磅发布Magentic UI,交互式AI Agent助手实测!

微软重磅发布Magentic UI,交互式AI Agent助手实测! 何为Magentic UI? Magentic UI 是微软于5.19重磅发布的开源Agent助手,并于24日刚更新了第二个版本0.04版 从官方的介绍来看,目标是打造一款 以人为中心 的智能助手,其底层由多个不同的智能体系统驱动,能够实现网页浏览…...

【C++系列】模板类型特例化

1. C模板类型特例化介绍 ​​定义​​&#xff1a;模板类型特例化&#xff08;Template Specialization&#xff09;是C中为模板的特定类型提供定制实现的机制&#xff0c;允许开发者对通用模板无法处理的特殊类型进行优化或特殊处理。 ​​产生标准​​&#xff1a; C98/03…...