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

java中创建多线程的4种方式

目录

一、继承 Thread 类创建线程

步骤

示例代码

原理

二、实现 Runnable 接口创建线程

步骤

示例代码

原理

三、实现 Callable 接口创建线程

步骤

示例代码

原理

与Runnable接口相比的不同之处

四、使用线程池创建线程

步骤

示例代码(使用 Executors.newFixedThreadPool)

原理

线程池的优势

自定义线程池

五、总结


        在 Java 编程中,多线程是一项非常重要的技术,它能够充分利用计算机的多核处理器资源,提高程序的执行效率和响应性。本文将详细介绍 Java 中创建多线程的四种方式,包括继承 Thread 类、实现 Runnable 接口、实现 Callable 接口以及使用线程池,并对每种方式的原理、代码示例和适用场景进行深入剖析。

一、继承 Thread 类创建线程

步骤

  • 创建一个类继承自 Thread 类。
  • 重写 run 方法,在 run 方法中定义线程要执行的任务。
  • 创建该类的实例,然后调用 start 方法启动线程。

示例代码

class MyThread extends Thread{// Ctrl + o// 展示所有的可以重写的方法@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("数据:"+i);}}
}
public class Demo01 {/***  第一种方案,继承Thread类  重写run方法 实现* @param args*/public static void main(String[] args) {// 在Main方法中,启动了一个子线程,子线程什么时候工作MyThread thread = new MyThread();thread.start();// 启动一个线程,调用start方法,不要调用run方法// 一个线程类,是可以创建多个不同的子线程的MyThread thread2 = new MyThread();thread2.start();// 启动一个线程,调用start方法,不要调用run方法// 主线程,直接运行代码   会出现子线程和主线程抢占资源的情况for (int i = 10; i < 100; i++) {System.err.println("Main:"+i);}}
}

原理

        当调用 start 方法时,会在新的线程中执行 run 方法。需要注意的是,start 方法只是启动线程,不会立即执行 run 方法。线程要等待获取 CPU 资源后才会执行 run 方法,而且在执行过程中可能会被其他线程抢占 CPU 资源。

二、实现 Runnable 接口创建线程

步骤

  • 创建一个类实现 Runnable 接口。
  • 实现 run 方法,在 run 方法中定义线程要执行的任务。
  • 创建 Runnable 接口实现类的实例,将其作为参数传递给 Thread 类的构造函数,然后调用 start 方法启动线程。

示例代码

class A implements Runnable{@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println(Thread.currentThread().getName()+":"+i);}}
}
public class Demo03 {/***  多线程创建的第二种方式,使用 Runnable接口*  该接口还需要传递给Thread类才能启动,否则自己启动不了**  两种方式:推荐使用第二种*   1、Thread类是一个线程类,它只需要管理好线程就行了,不需要管业务怎么写*   2、具体的业务可以交给Runnable接口实现*   3、java是单继承的,继承了Thread,就无法继承别的类了,但是可以实现多个接口。*/public static void main(String[] args) {A a = new A();new Thread(a).start();// Runnable接口本身就是一个函数式接口,就可以使用lambda表达式,代码可以简化为如下:new Thread( ()-> {for (int i = 0; i < 1000; i++) {System.out.println(Thread.currentThread().getName()+":"+i);}}).start();for (int i = 0; i < 1000; i++) {System.err.println(Thread.currentThread().getName()+":"+i);}}
}

原理

        Runnable 接口定义了一个无返回值的 run 方法,用于包含线程要执行的代码。Thread 类的构造函数可以接收一个 Runnable 接口的实现对象,当调用 Thread 的 start 方法时,会在新的线程中执行 Runnable 对象的 run 方法。这种方式比继承 Thread 类更灵活,因为 Java 是单继承的,如果一个类已经继承了其他类,就不能再继承 Thread 类了,但是可以实现 Runnable 接口来实现多线程。

三、实现 Callable 接口创建线程

步骤

  • 创建一个类实现 Callable 接口,该接口是一个函数式接口,有一个泛型参数,用于指定返回值类型。
  • 实现 call 方法,在 call 方法中定义线程要执行的任务,并返回一个结果。
  • 创建 Callable 接口实现类的实例,将其包装在一个 FutureTask 对象中,FutureTask 实现了 RunnableFuture 接口,而 RunnableFuture 接口继承了 Runnable 和 Future 接口。
  • 将 FutureTask 对象作为参数传递给 Thread 类的构造函数,然后调用 start 方法启动线程。可以通过 FutureTask 的 get 方法获取 call 方法的返回结果。

示例代码

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;class MyCall implements Callable<Integer>{@Overridepublic Integer call() throws Exception {return 200;}
}class MyRun implements Runnable{@Overridepublic void run() {System.out.println("我是子线程....");}
}
public class Demo08 {public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask<Integer> futureTask = new FutureTask<>(new MyCall());new Thread(futureTask,"计算线程").start();Integer i = futureTask.get();System.out.println(i);// --------------------------------------new Thread(new MyRun()).start();// ------------------使用callable 模拟 子线程进行大量计算并返回结果------------------FutureTask<Integer> f1 = new FutureTask<>(()->{System.out.println(Thread.currentThread().getName()+"  come in callable");TimeUnit.SECONDS.sleep(4);return 1024;});FutureTask<Integer> f2 = new FutureTask<>(()->{System.out.println(Thread.currentThread().getName()+"  come in callable");TimeUnit.SECONDS.sleep(4);return 2048;});new Thread(f1,"线程一:").start();new Thread(f2,"线程二:").start();while(!f1.isDone()){System.out.println("f1  wait中.....");}while(!f2.isDone()){System.out.println("f2  wait中.....");}// 其实 get 获取不到值会一直阻塞,直到获取到值为止int a = f1.get();int b = f2.get();System.out.println(a+b);}
}

原理

        Callable 接口与 Runnable 接口类似,但是 Callable 接口的 call 方法可以有返回值,并且可以抛出异常。FutureTask 用于包装 Callable 对象,它可以在未来某个时刻获取 call 方法的返回结果。通过这种方式,可以实现有返回值的多线程任务。

与Runnable接口相比的不同之处

(1)是否有返回值

(2)是否抛异常
(3)落地方法不一样,一个是run,一个是call

四、使用线程池创建线程

步骤

  • 通过 Executors 工具类的静态方法(如 newFixedThreadPoolnewCachedThreadPoolnewSingleThreadExecutor)创建一个线程池对象,或者直接使用 ThreadPoolExecutor 类来创建自定义的线程池。
  • 创建 Runnable 或 Callable 接口实现类的实例,作为任务提交给线程池。对于 Runnable 任务,可以使用 execute 方法提交;对于 Callable 任务,可以使用 submit 方法提交。

示例代码(使用 Executors.newFixedThreadPool

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyThreadPoolDemo {public static void main(String[] args) {//       ExecutorService threadPool =  Executors.newFixedThreadPool(5); //一个银行网点,5个受理业务的窗口
//       ExecutorService threadPool =  Executors.newSingleThreadExecutor(); //一个银行网点,1个受理业务的窗口ExecutorService threadPool =  Executors.newCachedThreadPool(); //一个银行网点,可扩展受理业务的窗口//10个顾客请求try {for (int i = 1; i <=10; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t 办理业务");});}} catch (Exception e) {e.printStackTrace();} finally {threadPool.shutdown();}}
}

原理

        线程池用于管理和复用线程。当提交一个任务到线程池时,线程池会根据自身的状态和配置来决定如何处理任务。如果线程池中有空闲线程,就会将任务分配给空闲线程执行;如果没有空闲线程且线程数量未达到最大限制,就会创建新的线程来执行任务;如果线程数量达到最大限制且任务队列已满,会根据线程池的拒绝策略来处理任务。这样可以有效地控制线程的数量,提高系统的性能和资源利用率,减少线程创建和销毁的开销。

线程池的优势

线程池做的工作只要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。

它的主要特点为:线程复用;控制最大并发数;管理线程。

第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的销耗。

第二:提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立即执行。

第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会销耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

Java中的线程池是通过Executor框架实现的,该框架中用到了Executor,Executors,ExecutorService,ThreadPoolExecutor这几个类。

经常使用的线程池做法

1、Executors.newFixedThreadPool(int)

执行长期任务性能好,创建一个线程池,一池有N个固定的线程,有固定线程数的线程

newFixedThreadPool创建的线程池corePoolSize和maximumPoolSize值是相等的,它使用的是LinkedBlockingQueue

2、Executors.newSingleThreadExecutor()

一个任务一个任务的执行,一池一线程。

newSingleThreadExecutor 创建的线程池corePoolSize和maximumPoolSize值都是1,它使用的是LinkedBlockingQueue

3、Executors.newCachedThreadPool()

执行很多短期异步任务,线程池根据需要创建新线程,但在先前构建的线程可用时将重用它们。可扩容,遇强则强。

newCachedThreadPool创建的线程池将corePoolSize设置为0,将maximumPoolSize设置为Integer.MAX_VALUE,它使用的是SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程。

自定义线程池


虽然根据API 我们能很轻松的使用到线程池,但是在实际开发中我们经常自定义线程池,怎么做呢?

参数说明

1、corePoolSize:线程池中的常驻核心线程数
2、maximumPoolSize:线程池中能够容纳同时执行的最大线程数,此值必须大于等于1
3、keepAliveTime:多余的空闲线程的存活时间   
当前池中线程数量超过corePoolSize时,当空闲时间达到keepAliveTime时, 多余线程会被销毁直到只剩下corePoolSize个线程为止。
4、unit:keepAliveTime的单位 
5、workQueue:任务队列,被提交但尚未被执行的任务  就是我们之前讲的阻塞队列
6、threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程,一般默认的即可
7、handler:拒绝策略,表示当队列满了,并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何来拒绝
请求执行的runnable的策略

线程池的拒绝策略

AbortPolicy(默认):直接抛出RejectedExecutionException异常阻止系统正常运行。
CallerRunsPolicy:“调用者运行”一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,俗称从哪儿来到哪儿去。
DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加人队列中尝试再次提交当前任务。
DiscardPolicy:该策略默默地丢弃无法处理的任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种策略。

以上内置拒绝策略均实现了RejectedExecutionHandle接口

1、在创建了线程池后,线程池中的线程数为零。

2、当调用execute()方法添加一个请求任务时,线程池会做出如下判断:

        2.1如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务;

        2.2如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列;

        2.3如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;

        2.4如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。

3、当一个线程完成任务时,它会从队列中取下一个任务来执行。

4、当一个线程无事可做超过一定的时间(keepAliveTime)时,线程会判断:

        如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。

        所以线程池的所有任务完成后,它最终会收缩到corePoolSize的大小。

 示例代码

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
/*** 线程池* Arrays* Collections* Executors*/
public class MyThreadPoolDemo {public static void main(String[] args) {ExecutorService threadPool = new ThreadPoolExecutor(2,5,2L,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),//new ThreadPoolExecutor.AbortPolicy()//new ThreadPoolExecutor.CallerRunsPolicy()//new ThreadPoolExecutor.DiscardOldestPolicy()new ThreadPoolExecutor.DiscardOldestPolicy());//10个顾客请求try {for (int i = 1; i <= 10; i++) {threadPool.execute(() -> {System.out.println(Thread.currentThread().getName() + "\t 办理业务");});}} catch (Exception e) {e.printStackTrace();} finally {threadPool.shutdown();}}
}

五、总结

        Java 提供了多种创建多线程的方式,每种方式都有其特点和适用场景。继承 Thread 类简单直接,适用于简单的线程任务;实现 Runnable 接口更加灵活,适合在已有类层次结构中使用多线程;实现 Callable 接口可用于需要获取线程执行结果的场景;使用线程池则可以高效地管理和复用线程,适用于需要大量线程处理任务的情况,并且可以通过合理配置线程池参数来优化系统性能。在实际开发中,需要根据具体的需求和场景选择合适的多线程创建方式,以充分发挥多线程编程的优势,提高程序的质量和效率。

相关文章:

java中创建多线程的4种方式

目录 一、继承 Thread 类创建线程 步骤 示例代码 原理 二、实现 Runnable 接口创建线程 步骤 示例代码 原理 三、实现 Callable 接口创建线程 步骤 示例代码 原理 与Runnable接口相比的不同之处 四、使用线程池创建线程 步骤 示例代码&#xff08;使用 Executo…...

MATLAB深度学习(二)——如何训练一个卷积神经网路

2.1 基本概念 从数学的角度看&#xff0c;机器学习的目标是建立输入和输出的函数关系&#xff0c;相当于 y F&#xff08;x&#xff09;的过程。F&#xff08;x&#xff09;就是我们所说的模型&#xff0c;对于使用者来说&#xff0c;这个模型就是一个黑箱&#xff0c;我们不知…...

删除k8s 或者docker运行失败的脚本

vi delete_exited_containers.sh#!/bin/bash# 列出所有停止的容器并存储到数组 list_exited_containers() {echo -e "\nStopped containers:"containers()# 获取停止的容器信息并存入数组while IFS read -r line; docontainers("$line")done < <(do…...

重置docker版本的octoprint管理员账号密码

我的情况是octoprint安装在HiNAS系统的机顶盒上&#xff0c;只有一个账号&#xff0c;但是忘记了用户名和密码。有两个选择&#xff1a; 可以试试先找回用户名&#xff0c;然后尝试你的常用密码。直接重置所有账号。 1.找回用户名&#xff1a; 使用使用 docker exec -it <…...

prometheus监控数据远程写入Kafka集群

文章目录 前言一、环境简介1.1 环境简介1.2 部署清单1.3 组件版本 二、部署步骤2.1 prometheus部署2.2 kafka集群部署2.3 prometheus-kafka-adapter部署 三、数据验证四、总结 前言 根据项目要求&#xff0c;需将prometheus监控数据存储到kafka中。前面为了图方便就搭建了单机…...

Excel使用-弹窗“此工作簿包含到一个或多个可能不安全的外部源的链接”的发生与处理

文章目录 前言一、探讨问题发生原因1.引入外部公式2.引入外部数据验证二、问题现象排查及解决1.排查公式2.排查数据验证3.特殊处理方式总结前言 作为一种常用的办公软件,Excel被大家所熟知。尽管使用了多年,有时候在使用Excel时候也会发生一些不太常见的现象,需要用心核查下…...

C++小白实习日记——Day 2 TSCNS怎么读取当前时间

和老板问了一下&#xff0c;今天就可以自己上手了&#xff1a; 用TSCNS写了一个cpp,运行出来老板说让我去看看另一个项目是怎么做的 用TSCNS和std库获取当前时间 #include <iostream> #include <iomanip> #include "tscns.h"using namespace std;TSCN…...

【Pythonr入门第二讲】你好,世界

"Hello, World!" 是一种传统的编程入门示例&#xff0c;通常是程序员学习一门新编程语言时编写的第一个程序。这个程序的目标非常简单&#xff1a;在屏幕上输出 "Hello, World!" 这个字符串。尽管它非常简单&#xff0c;但具有重要的象征意义和实际价值。 …...

3D Streaming 在线互动展示系统:NVIDIA RTX 4090 加速实时渲染行业数字化转型

随着科技的飞速发展&#xff0c;实时渲染正逐步成为游戏与实时交互领域的重要驱动力。与离线渲染不同&#xff0c;实时渲染需要极高的计算性能&#xff0c;对硬件设备尤其是GPU的性能要求极高。随着 RTX 4090 显卡的问世&#xff0c;其强大的算力和创新技术&#xff0c;为实时渲…...

Oracle 单机及 RAC 环境 db_files 参数修改

Oracle 数据库中 DB_FILES 定义了数据库中数据文件的个数&#xff0c;默认值为200&#xff0c;如果创建数据库文件时超过DB_FILES 定义的值就会报 ORA-00059 错误。 下面分别演示单机及 RAC 环境下修改 db_files 参数的操作步骤。 一、单机环境 1.查询当前参数值 SQL> sh…...

消息中间件分类

消息中间件&#xff08;Message Middleware&#xff09;是一种在分布式系统中实现跨平台、跨应用通信的软件架构。它基于消息传递机制&#xff0c;允许不同系统、不同编程语言的应用之间进行异步通信。 常见的消息中间件类型包括&#xff1a; 1. JMS&#xff08;Java Message S…...

讯飞、阿里云、腾讯云:Android 语音合成服务对比选择

在 移动端 接入语音合成方面&#xff0c;讯飞和腾讯云等都是优秀的选择&#xff0c;但各有其特点和优势。咱们的需求是需要支持普通话/英语/法语三种语言&#xff0c;以下是对各个平台的详细比较&#xff1a; 一、讯飞语音合成介绍 与语音听写相反&#xff0c;语音合成是将一段…...

SpringBoot开发——整合AJ-Captcha实现安全高效的滑动验证码

文章目录 一、什么是AJ-Captcha二、项目配置1、Maven依赖配置2、滑动验证码的基本原理3、 后端实现3.1 生成滑动验证码图片代码解释3.2 校验滑块位置代码解释4、前端部分代码解释5、Redis 缓存滑动验证码信息5.1 Redis配置5.2使用Redis缓存验证码数据5.3 校验时从Redis获取总结…...

Spring Security 核心组件

Spring Security 是一个功能全面的安全框架&#xff0c;用于处理基于 Spring 应用程序的身份验证和授权。 它提供了开箱即用的支持&#xff0c;采用行业标准的做法和机制来保护你的应用。 无论你是开发简单的 Web 应用还是复杂的微服务架构&#xff0c;理解 Spring Security …...

聚焦 AUTO TECH 2025华南展:探索新能源汽车发展新趋势

随着“新四化”浪潮的推进&#xff0c;汽车行业正经历前所未有的变革。中国新能源汽车正逐渐走向世界。国内汽车制造巨头如比亚迪、吉利、奇瑞、长安等&#xff0c;已经将出口提升至核心战略地位。中国新能源汽车的发展&#xff0c;不仅推动了全球汽车产业的电动化转型&#xf…...

Python-简单病毒程序合集(一)

前言&#xff1a;简单又有趣的Python恶搞代码&#xff0c;往往能给我们枯燥无味的生活带来一点乐趣&#xff0c;激发我们对编程的最原始的热爱。那么话不多说&#xff0c;我们直接开始今天的编程之路。 编程思路&#xff1a;本次我们将会用到os,paltform,threading,ctypes,sys,…...

[STM32]从零开始的STM32 HAL库环境搭建

一、前言 之前在搭建STM32的标准库环境时就告诉过大家&#xff0c;开发STM32的方式主要有三种。一种是最原始但是效率最高的寄存器开发&#xff0c;另一种是效率仅次于寄存器难度相对较低的标准库开发&#xff0c;最后一种是最为简单但是程序效率最低的HAL库开发。如果对于初学…...

Docker部署Kafka SASL_SSL认证,并集成到Spring Boot

1&#xff0c;创建证书和密钥 需要openssl环境&#xff0c;如果是Window下&#xff0c;下载openssl Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 还需要keytool环境&#xff0c;此环境是在jdk环境下 本案例所使用的账号密码均为&#xff1a; ka…...

Pr:音频过渡

Adobe Premiere Pro 自带一组共三个音频过渡 Audio Transitions效果。 对音频剪辑之间应用交叉淡化 Crossfade过渡&#xff0c;操作方式类似于应用视频过渡效果。 对于交叉淡化&#xff0c;要保证前剪辑的出点之后及后剪辑的入点之前有足够的预留内容&#xff08;也称“手柄”&…...

HarmonyOs鸿蒙开发实战(17)=>沉浸式效果第二种方案一组件安全区方案

1.沉浸式效果的目的 开发应用沉浸式效果主要指通过调整状态栏、应用界面和导航条的显示效果来减少状态栏导航条等系统界面的突兀感&#xff0c;从而使用户获得最佳的UI体验。 2.组件安全区方案介绍 应用在默认情况下窗口背景绘制范围是全屏&#xff0c;但UI元素被限制在安全区内…...

从 const 到 mutable:C++ 中的优雅妥协与设计智慧

在C编程中&#xff0c;const 关键字被广泛应用于确保数据的不变性&#xff0c;它提供了一种强大的机制来防止意外修改&#xff0c;从而增强了代码的可靠性和可维护性。然而&#xff0c;在某些特定场景下&#xff0c;完全的不变性可能会限制设计的灵活性&#xff0c;这时 mutabl…...

CC工具箱使用指南:【CAD导出界址点Excel】

一、简介 群友定制工具。 面图层导出界址点Excel表之前已经做过好几个&#xff0c;这个工具则是将CAD导出Excel。 CAD数据如下&#xff1a; 工具将如上截图中的边界线导出界址点Excel&#xff0c;并记录下面内的文字。 二、工具参数介绍 点击【定制工具】组里的【CAD导出界…...

制作图片马常用的五种方法总结

目录 1. 以文本方式2. Windows的cmd方式3. PhotoShop方式4. 16进制5. Linux的cat方式 图片马:就是在图片中隐藏一句话木马。利用.htaccess等解析图片为PHP或者asp文件。达到执行图片内代码目的。 1. 以文本方式 用文本方式&#xff08;这里用notepad。如果用记事本的方式打开…...

深入解析MySQL中的事务处理

一、引言 事务是数据库管理系统执行过程中的一个逻辑单位&#xff0c;它由一系列操作组成&#xff0c;这些操作要么全部执行&#xff0c;要么全部不执行。事务在保证数据的一致性、隔离性、持久性方面发挥着重要作用。MySQL作为一个广泛使用的数据库管理系统&#xff0c;对事务…...

TCP Analysis Flags 之 TCP Dup ACK

前言 默认情况下&#xff0c;Wireshark 的 TCP 解析器会跟踪每个 TCP 会话的状态&#xff0c;并在检测到问题或潜在问题时提供额外的信息。在第一次打开捕获文件时&#xff0c;会对每个 TCP 数据包进行一次分析&#xff0c;数据包按照它们在数据包列表中出现的顺序进行处理。可…...

r-and-r——提高长文本质量保证任务的准确性重新提示和上下文搜索的新方法可减轻大规模语言模型中的迷失在中间现象

概述 随着大规模语言模型的兴起&#xff0c;自然语言处理领域取得了重大发展。这些创新的模型允许用户通过输入简单的 "提示 "文本来执行各种任务。然而&#xff0c;众所周知&#xff0c;在问题解答&#xff08;QA&#xff09;任务中&#xff0c;用户在处理长文本时…...

光伏电站的方案PPT总结

现在的市面上每做一个项目&#xff0c;做个项目方案是必不可少的了&#xff0c;光伏电站的项目亦是如此&#xff0c;做一个既美观又有说服力的项目PPT方案就尤为重要&#xff0c;项目PPT方案的全面性&#xff0c;美观度更征服业主&#xff0c;拿下项目&#xff0c;下面我从鹧鸪…...

前端pdf预览方案

前端pdf预览方案 pdf预览一般不需要前端生成pdf文件&#xff0c;pdf文件一般是通过接口&#xff0c;获取pdf文件【responseType:‘blob’,】或二进制文件流【responseType: ‘arraybuffer’,】或者已有的pdf文件。 前端PDF预览通常是通过读取现有的PDF文件&#xff0c;并使用…...

java 深拷贝 浅拷贝 详解

在 Java 中&#xff0c;深拷贝和浅拷贝是对象拷贝&#xff08;复制&#xff09;时的两个重要概念&#xff0c;它们决定了拷贝后的对象与原对象之间的关联性。以下是深拷贝和浅拷贝的详解&#xff0c;包括定义、实现方式及其区别。 1. 概念解释 1.1 浅拷贝&#xff08;Shallow …...

针对git、giteeVSCode连接的使用 || Live Share插件使用

1.下载git 链接 打开终端&#xff0c;桌面鼠标右键 2.配置密钥 登录gitee。 设置密钥 查看官方文档 跟着教程 复制最后的输出进行密钥添加 验证是否添加成功 3.创建&连接远程仓库 创建仓库 git终端进行配置 远程仓库克隆到本地 桌面终端clone,克隆他人|自己的仓库到本地…...

杭州网站建设找思创网络/百度收录入口提交查询

为什么80%的码农都做不了架构师&#xff1f;>>> 一、SocketChannel和KafkaChannel有什么区别&#xff1f; 上篇文章说道KafkaSelector在创建一个连接的时候和普通的nioSelector并没有什么不同&#xff0c;它是基于nioSelector的封装。我们知道创建连接的一系列操作…...

做网站需要独立ip吗/做推广app赚钱的项目

题意&#xff1a;给你一个n*m的棋盘&#xff0c;问你最多可以放几个马&#xff0c;他们之间互不攻击。 xmin(n,m),ymax(n,m) 当x1时&#xff0c;输出y。 当x2时&#xff0c;输出我们可以放若干个田字。 当x>2时&#xff0c;我们全放在白格子或者黑格子上面。 #include &…...

记事本做网站怎么加背景图/网站百度seo关键词优化

今天给大家筛选了8本侧重基础的ABAQUS书籍&#xff0c;大家可根据自己的学习需求阅读练习。ABAQUS6.6基础教程与实例详解作者&#xff1a;刘展出版社&#xff1a;中国水利水电出版社简介&#xff1a;本书全面系统地介绍了ABAQUS6.6的使用。分为两部分&#xff0c;第1部分为ABAQ…...

网站 申请/知乎推广合作

今天我们来聊点接地气的话题&#xff0c;比如关心一下粮食和蔬菜。这就不得不提到中国人最不容置喙的种族天赋&#xff0c;那就是种地&#xff01;种地&#xff0c;让我们充满了想象力。有条件要种&#xff0c;没有条件创造条件也要种&#xff1a;种地&#xff0c;让我们团结一…...

莱芜融媒体中心网站/百度搜索引擎营销如何实现

在发展工业物联网 (IoT) 以及满足相关的工业传感器无线连网需求方面&#xff0c;已经做了很多。不过&#xff0c;工业设备及应用的网络需求与家用环境完全不同&#xff0c;可靠性和安全性是高居工业应用要求的榜首。本文重点讨论特定于工业无线传感器网络的一些关键网络要求。 …...

金钟街网站建设哪家好/网络营销教学网站

一面&#xff1a; python题&#xff1a; is了解吗&#xff1f; python中的self python中的lambda python中的with python中的循环引用 算法题&#xff1a;python实现单例模式 算法题&#xff1a;翻转字符串 算法题&#xff1a;找出字符串的所有子字符串 算法题&#…...