Java 多线程基础

文章目录

  • 1. 认识线程
    • 1.1 概念
      • 1.1.1 线程是什么
      • 1.1.2 为什么要有线程
      • 1.1.3 进程和线程的区别
      • 1.1.4 Java的线程和操作系统线程的关系
    • 1.2 第一个多线程程序
    • 1.3 创建线程
    • 1.4 多线程的优势
  • 2. Thread 类及其常用的方法
    • 2.1 Thread 的常见构造方法
    • 2.2 Thread 的几个常见属性
    • 2.3 启动一个线程 - start()
    • 2.4 中断一个线程
    • 2.5 等待一个线程 - join()
    • 2.6 获取当前线程引用
    • 2.7 休眠当前线程

1. 认识线程

1.1 概念

1.1.1 线程是什么

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
一个线程就是一个"执行流", 每个线程可以按照顺序执行自己的代码, 多个线程之间"同时"执行着多份代码

1.1.2 为什么要有线程

  • 单核CPU的发展到了瓶颈, 要再想提高计算机算力的话, 就需要多核CPU, 而并发编程便能充分利用多核CPU资源
  • 有些任务场景需要"等待IO"为了让"等待IO"的时间能去做其他的事情, 也需要用到并发编程

虽然多进程也能实现并发编程, 但是多线程要比多进程更轻量

  • 创建线程比创建进程更快
  • 销毁线程比销毁进程更快
  • 调度线程比调度进程更快

1.1.3 进程和线程的区别

  • 进程是包含线程的, 每个进程必须包含一个线程, 就是主线程
  • 进程和进程之间是不共享内存空间的, 同一个进程的线程之间共享内存空间
  • 进程是系统分配资源的最小单位, 线程是系统调度的最小单位

1.1.4 Java的线程和操作系统线程的关系

线程是操作系统中的概念, 操作系统内核实现了这样的机制,并且对用户层提供了一些 API 供用户使
用(例如 Linux 的 pthread 库).
Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装

1.2 第一个多线程程序

下面我们写一个简单的多线程程序, 先不关心它是怎么写的, 就先简单的了解一下多线程,
感受多线程程序和单线程程序的区别

  • 每个线程是一个独立的执行流
  • 多个线程之间是"并发"执行的
package Thread;import java.util.Random;public class ThreadDemo1 {private static class MyThread extends Thread {@Overridepublic void run() {Random random = new Random();while (true) {// 打印线程的名称System.out.println(Thread.currentThread().getName());try {// 随机停止运行 0 ~ 9 秒Thread.sleep(random.nextInt(10));} catch (InterruptedException e) {throw new RuntimeException(e);}}}}public static void main(String[] args) {MyThread thread1 = new MyThread();MyThread thread2 = new MyThread();MyThread thread3 = new MyThread();// 启动线程thread1.start();thread2.start();thread3.start();Random random = new Random();while (true) {System.out.println(Thread.currentThread().getName());try {// 随机停止运行 0 ~ 9 秒Thread.sleep(random.nextInt(10));} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

在这里插入图片描述
下面我们用jconsole观察线程
首先我们打开jconsole
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.3 创建线程

  1. 继承Thread 类来创建一个线程
public class ThreadDemo2 {// 1.继承一个Thread 类来创建一个线程类class MyThread extends Thread {@Override// 重写里面的run方法public void run() {System.out.println("这里是线程运行的代码");}}public static void main(String[] args) {// 2.创建一个 MyThread 实例MyThread thread1 = new MyThread();// 3. 调用 start 方法启动线程thread1.start();}
}
  1. 实现 Runnable 接口
public class ThreadDemo3 {// 1. 实现Runnable接口static class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("这里是线程执行的代码");}}public static void main(String[] args) {// 2. 创建Thread类实例, 调用Thread类的构造方法时将Runnable对象作为target 参数Thread thread1 = new Thread(new MyRunnable());// 启动线程thread1.start();}
}

这里我们要注意的是:
实现Runnable接口,并不能直接启动或者说实现一个线程,Runnable接口和线程是两个不同的概念
换句话说,一个类,实现Runnable接口,这个类可以做很多事情,不仅仅只被用于线程,也可以用于其他功能!

  • 继承 Thread 类直接使用 this 就表示当前线程对象的引用
  • 而实现 Runnable 接口, this 表示的是 MyRunnable 的引用, 需要使用 Thread.currentThread() 表示当前线程对象的引用
  1. 使用匿名内部类创建 Thread 子类对象
public class ThreadDemo5 {public static void main(String[] args) {Thread thread1 = new Thread() {@Overridepublic void run() {System.out.println("使用匿名内部类创建 Thread 子类对象");}};//启动线程thread1.start();}
}
  1. 匿名内部类创建 Runnable 子类对象
public class ThreadDemo6 {public static void main(String[] args) {Thread thread1 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("使用匿名内部类创建 Runnable 子类对象");}});// 启动线程thread1.start();}
}
  1. lambda 表达式创建 Runnable 子类对象
public class ThreadDemo7 {public static void main(String[] args) {Thread thread1 = new Thread(() -> {System.out.println("使用匿名内部类创建 Thread 对象");});// 启动线程thread1.start();}
}

注:
Thread 类中run()和start()方法的区别

作用功能不同:
run方法的作用是描述线程具体要执行的任务;
start方法的作用是真正的去申请系统线程
运行结果不同:
run方法是一个类中的普通方法,主动调用和调用普通方法一样,会顺序执行一次;
start调用方法后, start方法内部会调用Java 本地方法(封装了对系统底层的调用)真正的启动线程,并执行run方法中的代码,run 方法执行完成后线程进入销毁阶段。

1.4 多线程的优势

多线程的主要优势之一就是增加运行速度

下面我们举个例子具体看
我们使用并发和串行方式计算 a 和 b 的值, 分别让 a 和 b 自加20_0000_0000次,

/*** @describe* @author chenhongfei* @version 1.0* @date 2023/9/23*/
package Thread;import java.util.Random;
import java.util.concurrent.CountDownLatch;public class ThreadDemo8 {private static final long count = 20_0000_0000;public static void main(String[] args) throws InterruptedException {// 使用并行方式concurrency();// 使用串行方式serial();}// 并行private static void concurrency() throws InterruptedException {long begin = System.nanoTime();// 利用一个线程计算 a 的值Thread thread1 = new Thread(new Runnable() {@Overridepublic void run() {int a = 0;for (int i = 0; i < count; i++) {a++;}}});//启动线程thread1.start();// 主线程内计算b的值int b = 0;for (int i = 0; i < count; i++) {b++;}// 等待Thread线程结束thread1.join();long end = System.nanoTime();double ms =  (end - begin) * 1.0 / 1000 /1000; //1 纳秒=1e-6 毫秒System.out.printf("并发: %f 毫秒%n",ms);}// 串行private static void serial() {// 全在主线程内计算a, b 的值long begin = System.nanoTime();int a = 0;int b = 0;for (int i = 0; i < count; i++) {a++;}for (int i = 0; i < count; i++) {b++;}long end = System.nanoTime();double ms =  (end - begin) * 1.0 / 1000 /1000; //1 纳秒=1e-6 毫秒System.out.printf("串行: %f 毫秒%n",ms);}
}

在这里插入图片描述

2. Thread 类及其常用的方法

Thread类是Java中用于创建线程的类。线程是程序执行的最小单元,它允许多个任务并发执行,提高了程序的效率。Thread类的实例表示一个独立的执行线程,可以通过继承Thread类或实现Runnable接口来创建线程。Thread类提供了一系列方法来管理线程的状态和行为,比如启动线程、暂停线程、恢复线程、等待线程完成等。在Java中,线程的使用非常普遍,比如在网络编程、多线程服务器、GUI应用程序等领域都会用到线程。

2.1 Thread 的常见构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名
Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("这是我的名字");
Thread t4 = new Thread(new MyRunnable(), "这是我的名字");

2.2 Thread 的几个常见属性

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

具体情况我们参考下面代码

/*** @describe* @author chenhongfei* @version 1.0* @date 2023/9/23*/
package Thread;public class ThreadDemo9 {public static void main(String[] args) {Thread thread1 = new Thread(() -> {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "我还活着");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(Thread.currentThread().getName() + "我即将死去");});System.out.println(Thread.currentThread().getName() + ": ID" + thread1.getId());System.out.println(Thread.currentThread().getName() + ": 名称" + thread1.getName());System.out.println(Thread.currentThread().getName() + ": 状态" + thread1.getState());System.out.println(Thread.currentThread().getName() + ": 优先级" + thread1.getPriority());System.out.println(Thread.currentThread().getName() + ": 后台线程" + thread1.isDaemon());System.out.println(Thread.currentThread().getName() + ": 活着" + thread1.isAlive());System.out.println(Thread.currentThread().getName() + ": 被中断" + thread1.isInterrupted());//启动线程thread1.start();while (thread1.isAlive()) {System.out.println(Thread.currentThread().getName() + ": 状态" + thread1.getState());}}
}

2.3 启动一个线程 - start()

在Java中,start()方法通常用于启动线程。它是定义在Thread类中的方法,用于启动线程。
当调用start()方法时,线程会从它的run()方法开始执行。run()方法是线程的执行体,它包含了线程要执行的代码。
当线程启动后,它将从run()方法开始执行,直到该方法结束或线程被中止。在执行期间,线程可以访问共享变量和对象,并且可以与其他线程并发执行。

  • 调用 start() 方法, 才真的在操作系统的底层创建出一个线程.
  • 重写run() 方法是给线程提供具体的指令清单
Thread thread = new Thread(new Runnable() {@Overridepublic void run() {// 线程执行的代码(重写run 方法)System.out.println("Thread started.");}
});
thread.start(); // 启动线程

在上面的示例中,我们创建了一个新的线程对象,将一个实现了Runnable接口的对象传递给了构造函数。在run()方法中,我们打印了一条消息表示线程已经启动。然后,我们调用start()方法来启动线程。
需要注意的是,start()方法并不会阻塞调用它的线程。启动线程后,程序会继续执行其他代码。如果需要等待线程执行结束后再继续执行当前线程,可以使用join()方法。

2.4 中断一个线程

一个线程一旦进到工作状态,他就会按照行动指南上的步骤去进行工作,不完成是不会结束的。但有时我们需要增加一些机制,例如老板突然来电话了,说转账的对方是个骗子,需要赶紧停止转账,那该如何通知这个线程停止呢?这就涉及到我们的停止线程的方式了。
下面我们介绍两种方式:

  • 1.通过共享的标记来进行沟通

通过设置一个标志位,线程在执行时可以检查这个标志位,如果发现标志位被设置了,那么线程就认为自己被中断了。

  • 2.调用interrupt() 方法来通知

下面是一个简单的使用标志位中断线程的实例:

public class ThreadDemo10 {private static volatile boolean isInterrupted = false;  //使用volatile 修饰, 保证线程间的可见性static Thread thread1 = new Thread(() -> {while (!isInterrupted) {System.out.println(Thread.currentThread().getName() + "开始转账");try {Thread.sleep(1000);  // 模拟任务耗时} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(Thread.currentThread().getName() + "取消转账, 差点误了大事");});public static void main(String[] args) {thread1.start();    // 线程启动, 开始转账isInterrupted = true;   // 取消转账}
}

我们也可以使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定义标志位.

Thread 内部包含了一个 boolean 类型的变量作为线程是否被中断的标记

下面先介绍几个方法

方法说明
public void interrupt()中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置标志位
public static booleaninterrupted()判断当前线程的中断标志位是否设置,调用后清除标志位
public booleanisInterrupted()判断对象关联的线程的标志位是否设置,调用后不清除标志位
public class ThreadDemo11 {static Thread thread1 = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {    // Thread.currentThread().isInterrupted() 这就是标志位System.out.println(Thread.currentThread().getName() + "开始转账");try {Thread.sleep(1000);  // 模拟任务耗时} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(Thread.currentThread().getName() + "取消转账, 差点误了大事");});public static void main(String[] args) {thread1.start();    // 线程启动, 开始转账thread1.interrupt();   //设置标志位   取消转账}
}

线程收到通知的方法有两种:

  1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通知,清除中断标志

当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择忽略这个异常, 也可以跳出循环结束线程.

  1. 否则, 只是内部的一个中断标志被设置,thread 可以通过:
    Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
    Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

标志位就相当于一个开关
Thread.isInterrupted() 相当于按下开关, 开关自动弹起来了, 这个称为"清楚标志位"
Thread.currentThread().isInterrupted() 相当于按下开关, 开关不弹起来, 这个称为"不清除标志位"

  • 使用Thread.isInterrupted() 线程中断, 会清除标志位
public class ThreadDemo12 {public static void main(String[] args) {Thread thread1 = new Thread(() -> {for (int i = 0; i < 10; i++) {System.out.println(Thread.interrupted());try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});thread1.start();thread1.interrupt();   // 通知中断线程, 设置标志位}
}

只有第一个是 true , 后面都是 false 因为"开关弹回去了"
在这里插入图片描述

  • 使用Thread.currentThread().Interrupted() 线程中断, 标志位不会清除

public class ThreadDemo13 {public static void main(String[] args) {Thread thread = new Thread(() -> {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().isInterrupted());}});thread.start();thread.interrupt();}
}

全部都是 true , 因为标志位不会清除
在这里插入图片描述

2.5 等待一个线程 - join()

有时候, 我们经常需要等待一个线程完成它的工作后, 才能进行下一步工作, 比如说, 这个月发工资我要买个手机, 只有等到了工资到账, 才能去买手机, 这时候我们就需要明确等待线程的结束.

每个Thread实例都有一个join()方法,该方法使得当前正在执行的线程暂停执行(阻塞),直到被join的线程执行结束(即从run()方法返回)。

public class ThreadDemo14 {public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("还有" + (5-i) +"天发工资");}System.out.println("工资已到账");});Thread thread2 = new Thread(() -> {System.out.println("正在去买手机的路上");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("买到了手机");});thread1.start();thread1.join();   //直到 thread1 执行结束才执行后面内容thread2.start();thread2.join();System.out.println("此任务结束");}
}

在这里插入图片描述
在这个例子中,主线程(Main Thread)会等待thread1线程执行结束,然后再执行自己的后续操作(让thread2执行)。join()方法的使用使得主线程能够同步地执行与子线程的结束。

如果把两个join() 注释掉, 效果如下:
在这里插入图片描述
此外还可以使用wait(), notify() 和 notifyAll(), 这个后面我们细说.

2.6 获取当前线程引用

方法说明
public static Thread currentThread();返回当前线程对象的引用
public class ThreadDemo {public static void main(String[] args) {Thread thread = Thread.currentThread();}
}

currentThread() 现在就是指向当前执行线程的一个引用。你可以用这个引用来获取当前线程的各种信息,例如它的名称、它的优先级、它是否是守护线程等等。

System.out.println("Current thread name: " + currentThread.getName());
System.out.println("Current thread priority: " + currentThread.getPriority());
System.out.println("Is current thread a daemon?: " + currentThread.isDaemon());

2.7 休眠当前线程

我们可以使用Thread.sleep()方法来使当前线程休眠(暂时停止执行)一段时间。这个方法接受一个以毫秒为单位的时间参数,指定线程应该休眠的时间。

  • 因为线程的调度是不可控的,所以,这个方法只能保证实际休眠时间是大于等于参数设置的休眠时间的。
public class ThreadDemo15 {public static void main(String[] args) {Thread thread1 = new Thread(() -> {System.out.println(System.currentTimeMillis());try {Thread.sleep(3 * 1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(System.currentTimeMillis());});thread1.start();}
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

EasyExcel导出转换@ExcelProperty注解中converter不生效,以及EasyExcel导入日期转换失败问题

用EasyExcel做导出&#xff0c;需要用ExcelProperty做格式转换&#xff0c;比如日期转换&#xff0c;枚举类转换 然后新建一个转换类 里面有两个实现方法&#xff0c;converToJavaData是导入时&#xff0c;数据转换定义格式&#xff0c;converToExcelData是导出时做数据转换的。…

一款强大的ntfs磁盘读写工具Paragon NTFS 15破解版百度网盘下载

今天再给大家分享一款NTFS工具Paragon NTFS 15&#xff0c;Paragon NTFS 15破解版是目前的最新版&#xff0c;需要的赶快收藏&#xff0c;地址失效可以留言。 Paragon Ntfs For Mac 15下载&#xff1a;https://souurl.cn/s84CCB Crcak链接: https://pan.baidu.com/s/1c2Hx7QBE…

idea环境下如何打包可运行jar?

工作中有时候偶尔写一些工具类、小程序&#xff0c;可是java程序员制作一个可运行jar实在折腾&#xff0c;利用idea开发环境&#xff0c;可以快速打包自己的可运行jar。具体怎么操作呢&#xff1f; 创建一个空白的java项目并完成自己的程序开发 完成java代码&#xff1a; /**…

SpringMVC 学习(四)RestFul 风格

5. RestFul 风格 5.1 简介 概念 Restful就是一个资源定位及资源操作的风格。不是标准也不是协议&#xff0c;只是一种风格。基于这个风格设计的软件可以更简洁&#xff0c;更有层次&#xff0c;更易于实现缓存等机制。 功能 资源&#xff1a;互联网所有的事物都可以被抽象为…

华为手机如何开启设置健康使用手机模式限制孩子玩手机时间?

华为手机如何开启设置健康使用手机模式限制孩子玩手机时间&#xff1f; 1、在手机上找到「设置」并点击打开&#xff1b; 2、在设置内找到「健康使用手机」并点击进入&#xff1b; 3、开启健康使用手机后&#xff0c;选择孩子使用&#xff1b; 4、在健康使用手机内&#xff0c…

【Java接口性能优化】skywalking使用

skywalking使用 提示&#xff1a;微服务中-skywalking使用 文章目录 skywalking使用一、进入skywalking主页二、进入具体服务1.查看接口 一、进入skywalking主页 二、进入具体服务 可以点击列表或搜索后&#xff0c;点击进入具体服务 依次选择日期、小时、分钟 1.查看接口 依次…

系统集成|第十二章(笔记)

目录 第十二章 沟通管理12.1 沟通的基本概念12.2 主要过程12.2.1 规划沟通管理12.2.2 管理沟通12.2.3 控制沟通 12.3 常见问题 上篇&#xff1a;第十一章、项目人力资源管理 下篇&#xff1a;第十三章、干系人管理 第十二章 沟通管理 沟通管理在项目计划、执行、监控过程中具有…

word中使用latex多行公式,矩阵公式

\eqarray{H& [h(x_1)^T,\cdots,h(x_N)^T]^T \\ & [\matrix{g(w_1 x_1b_1) & \cdots & g(w_L x_1b_L) \\ \vdots & \ddots & \vdots \\ g(w_1 x_Nb_1) & \cdots & g(w_L x_Nb_L)}]_{N \times L}}&的引起的那条竖线可以通过backspace或者del…

在 Substance Painter中实现Unity Standard Shader

由于有需要在Substance Painter中显示什么样的效果&#xff0c;在Unity就要显示什么样的效果的需求&#xff0c;最近研究了几天&#xff0c;总算在Substance Painter中实现Unity standard的材质的渲染效果。具体效果如下&#xff1a; 在Unity中&#xff1a; Substance Painte…

sdk下载慢的解决办法

Android studio版本&#xff1a;为Android Studio 4.1.1&#xff0c; 先完成Android Studio软件安装&#xff0c;打开Android Studio&#xff0c;点击File -> settings->Android SDK&#xff0c;按照开发需要安装sdk platform、SDK Tools工具。 sdk下载慢解决办法 1、…

面试必杀技:Jmeter性能测试攻略大全(第一弹)

前言 性能测试是一个全栈工程师/架构师必会的技能之一&#xff0c;只有学会性能测试&#xff0c;才能根据得到的测试报告进行分析&#xff0c;找到系统性能的瓶颈所在&#xff0c;而这也是优化架构设计中重要的依据。 第一章 测试流程&#xff1a; 需求分析→环境搭建→测试…

《玩转smardaten | GIS地图无码化配置全方位指南》

GIS地图作为一种特殊图表&#xff0c;将地理位置信息和地图结合起来进行处理、管理和分析。 这些地图可以让用户以多种方式查看、分析和解释地理数据&#xff0c;包括创建图层、生成主题地图和执行空间分析等&#xff0c;更加形象完整的辅助数据可视化。常用的场景如&#x1f…

MATLAB中norm函数用法

目录 语法 说明 示例 向量模 向量的 1-范数 两个点之间的欧几里德距离 矩阵的 2-范数 N 维数组的 Frobenius 范数 常规向量范数 norm函数的功能是计算向量范数和矩阵范数。 语法 n norm(v) n norm(v,p) n norm(X) n norm(X,p) n norm(X,"fro") 说明…

Python二级 每周练习题20

练习一: 日期计算器 设计一款日期计算程序&#xff0c;能否实现下面的功能&#xff1a; (1)要求用户分别输入年、月、日&#xff08;分三次输入&#xff09;&#xff1b; (2)程序自动会根据输入的年月日计算出这一天是这一年的第几天&#xff1b; (3)输出格式为&#xff1a;这…

Tomcat基础与优化

Tomcat介绍 Tomcat服务器是一个免费的开放源代码的Web应用服务器&#xff0c;属于轻量级应用服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c;Tomcat具有处理HTML页面的功能&#xff0c;通常作为一个Servlet和JSP容器&#xff0c;单独运行…

上网行为监管软件(上网行为管理软件通常具有哪些功能)

在我们的日常生活中&#xff0c;互联网已经成为了我们获取信息、交流思想、进行工作和娱乐的重要平台。然而&#xff0c;随着互联网的普及和使用&#xff0c;网络安全问题也日益突出&#xff0c;尤其是个人隐私保护和网络行为的规范。在这个背景下&#xff0c;上网行为审计软件…

蜜雪冰城涨价怒赞无数 雪王张红超卷出一条阳道

作者&#xff1a;积溪 简评&#xff1a;最近雪王涨价一元登上了热搜&#xff0c;但评论区却是一片和谐&#xff0c;雪王的魅力究竟是如何养成的&#xff1f;#蜜雪冰城 #雪王 #张红超 #奶茶 别的品牌涨价&#xff0c;只有吐槽声一片&#xff1b;但它涨价&#xff0c;却是网友们…

携手低代码平台公司,创造高效率办公!

当前&#xff0c;什么样的平台产品可以实现高效率办公&#xff1f;随着社会化发展程度的推进发展&#xff0c;很多客户朋友希望找到更理想的平台产品&#xff0c;助力企业管理好内部数据&#xff0c;起到链接互通各部门沟通桥梁的作用。低代码开发平台就是其中一种理想的得力助…

如何看待著名游戏引擎 Unity 宣布将更改收费模式,收取「运行时费用」?这将造成哪些影响?

先下结论&#xff1a;Unity 的高管是不是【不友善内容&#xff0c;请于 24 小时内及时更改】&#xff1f; 简单介绍下这个收费模式&#xff1a;年收入大于 20w 美金且安装量大于 20w 的&#xff0c;每一份额外下载需要给 Unity 交 0.2 刀。 首先&#xff1a;听上去好像不会影响…

使用显著性检测的可见光和红外图像的两尺度图像融合(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…