⛳ Java多线程 一,线程基础
线程基础
- ⛳ Java多线程 一,线程基础
- 🐾 一,线程基础
- 💭 1.1,什么是程序,进程,线程
- 🏭 1.2,什么是并行和并发
- 👣 1.3,线程使用的场景
- 🎨 1.4,创建线程
- 1.4.1,继承 `Thread`类的方式
- 1.4.2,实现`Runanble`接口:
- 1.4.3,`Thread` 常见方法
- 1.4.4,`sleep()`方法
- 1.4.5,线程优先级
- 1.4.6,守护线程
- 1.4.7,线程合并
- 1.4.8,线程退出
- 📢 1.5,线程的生命周期
- 1.5.1,线程的调度与时间片
- 1.5.2,线程状态
- 1.5.3,多线程自增 i++ 和线程执行原理
⛳ Java多线程 一,线程基础
当涉及多线程编程时,我们可以同时执行多个任务,从而提高程序的性能和响应性。然而,多线程编程也带来了一些挑战,比如线程同步和资源共享。在本教程中,我们将介绍Java中的多线程编程,包括创建和管理线程,线程同步,以及常见的多线程问题和解决方案。
🐾 一,线程基础
💭 1.1,什么是程序,进程,线程
在计算机科学中,程序(Program),进程(Process)和线程(Thread)是三个重要的概念,它们都与执行计算机任务和程序相关。
-
程序(Program):
程序是一系列指令的集合,这些指令按照特定的顺序组织,用于完成特定的任务或执行特定的操作。程序是静态的,它们只是存储在计算机磁盘或存储设备中,并不直接执行。当我们想要运行一个程序时,操作系统会将程序加载到内存中,并将其转换为进程,然后才能执行其中的指令。
-
进程(Process):
进程是计算机程序在执行时的实例。它是计算机中正在运行的程序的活动副本。每个进程都有自己独立的内存空间,包含程序代码、数据、堆栈等信息。进程之间相互隔离,一个进程的崩溃不会影响其他进程的稳定性。每个进程在操作系统中都有自己的标识符(Process ID),它可以用来管理和监控进程的状态。
进程有以下特点:
- 进程之间相互隔离,一个进程的崩溃不会影响其他进程的稳定性。每个进程在操作系统中都有自己的标识符(Process ID),它可以用来管理和监控进程的状态。
- 资源分配:每个进程拥有自己的内存空间和系统资源。
- 切换开销:在进程之间切换会导致一定的开销,因为需要保存和恢复各个进程的上下文。
-
线程(Thread):
线程是进程中的执行单元,每个进程可以包含多个线程。线程与进程共享相同的内存空间,因此它们可以更轻松地相互通信。多线程在多核处理器上能够实现并行执行,从而提高程序的性能和响应性。
线程有以下特点:
-
共享资源:线程之间共享进程的内存和资源,可以更方便地交换数据和信息。
-
轻量级:相较于进程,线程的创建、切换和销毁开销较小。
-
同步问题:多线程共享资源可能导致同步问题,需要采取同步机制来避免数据冲突。
总结:
程序是一组指令的集合,进程是程序在执行时的实例,而线程是进程中的执行单元。进程之间相互独立,而线程共享同一进程的资源。多线程在并行处理和提高程序性能方面具有优势,但同时也需要注意处理线程同步问题。
-
🏭 1.2,什么是并行和并发
并行(Parallel /ˈpærəlel/ )和并发(Concurrent /kənˈkʌrənt/)是两个与计算机执行任务相关的重要概念。
-
并行(Parallel):
并行是指同时执行多个任务或操作。在计算机中,当多个处理器核心或计算单元同时执行不同的任务或同一个任务的不同部分时,我们称之为并行执行。这样可以显著提高计算机系统的处理能力和效率,特别时在多核处理器上。
举例来说,如果有一个任务要处理一系列的数据,那么在并行处理中,不同的处理器核心可以同时处理这些数据的不同部分,从而更快地完成任务。
-
并发(Concurrent):
并发是指同时处理多个任务,但并不一定是同时执行这些任务。在计算机中,并发执行是通过快速的任务切换和调度来实现的,操作系统会以非常小的时间片轮流执行多个任务,让它们看起来是同时进行的。
举例来说,如果有两个任务要处理,操作系统可以分别给它们分配时间片,让它们交替执行,从用户的角度来看,好像这两个任务在同时进行。
关键区别: 并行是真正的同时执行多个任务,需要多个处理器核心或计算单元支持。而并发是通过快速的切换和调度,让多个任务交替执行,从用户的角度来看,好像这些任务在同时进行,但实际上是在时间上错开的。
总结:
并行是真正的同时执行多个任务,利用多核处理器等技术提高计算效率;而并发是通过任务切换和调度,让多个任务交替执行,实现任务间的快速切换,从用户角度看起来是同时执行的。并行适合利用多核处理器等资源来加速计算,而并发适合在单核处理器上实现任务的高效利用。
👣 1.3,线程使用的场景
线程在计算机编程和软件开发中有许多使用场景。
它们主要用于以下情况:
- 并发执行:线程使得程序能够同时处理多个任务,特别是在多核处理器上能够实现真正的并行执行。例如,一个计算密集型的应用程序可以将任务分成多个线程,在多核处理器上同时执行,提高整体性能。
- 多任务处理:线程可以用于在单个应用程序内执行多个任务,使得程序能够同时响应多个用户请求或事件。例如,一个服务器应用程序可以使用多线程来同时处理多个客户端请求。
- 用户界面响应:在图形用户界面(GUI)应用程序中,线程用于保持用户界面的响应性。将耗时的任务(如文件加载、网络请求等)放在后台线程中执行,以免阻塞用户界面的操作。
- 并行算法:在某些计算密集型任务中,可以使用线程实现并行算法,将计算任务分成多个部分并在不同线程中并行执行,从而加快计算速度。
- 服务器应用:在服务器端应用程序中,线程用于同时处理多个客户端连接请求,实现高并发处理能力。
- 多媒体处理:在音频、视频处理等应用中,线程可用于同时处理多个媒体流,实现流畅的播放和录制。
- 游戏开发:在游戏开发中,线程通常用于同时处理游戏逻辑、图形渲染和用户输入,以提供流畅的游戏体验。
需要注意的是,虽然线程在很多情况下能够提高程序的性能和响应性,但多线程编程也带来了一些挑战,如数据同步与竞争条件。正确地处理线程同步和资源共享问题对于编写稳定和可靠的多线程应用程序至关重要。因此,在使用线程时,开发人员需要仔细考虑并采取适当的同步措施,以避免潜在的问题。
🎨 1.4,创建线程
有两种方式可以创建线程:
1,继承
Thread
类并重写run()
方法;2,实现
Runnable
接口;
1.4.1,继承 Thread
类的方式
- 定义子类继承
Thread
类。 - 类中重写
Thread
类中的run
方法。 - 创建
Thread
子类对象,即创建了线程对象。 - 调用线程对象
start
方法:启动线程,调用run
方法。
案例:
启动一个线程,在线程中执行1-10000的偶数打印工作:
public class MyThread extends Thread {@Overridepublic void run() {for (int i = 1; i <= 10000; i++) {if (i % 2 == 0) {//Thread.currentThread().getName():得到线程的名字System.out.println(Thread.currentThread().getName() + "\t" + i);}}}
}
测试:
public class Test1 {public static void main(String[] args) {MyThread myThread1 = new MyThread();myThread1.start();MyThread myThread2 = new MyThread();myThread2.start();System.out.println(Thread.currentThread().getName() + " main 线程 over");}
}
JOptionPane.showMessageDialog(null, "是否确认向下执行...."); //主线程进入IO阻塞System.out.println("main over");
- 如果子线程执行,进程不会停止。
1.4.2,实现Runanble
接口:
- 定义子类,实现Runnable接口。
- 类中重写Runnable接口中的run方法。
- 通过Thread类含参构造器创建线程对象。
- 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
- 调用Thread类的start方法:开启线程, 调用Runnable子类接口的run方法。
public class ThreadDemo {public static void main(String[] args) {//方式1:Thread子类,启动MyThread thread1 = new MyThread();thread1.start();//方式2:Runable方式(推荐的方式)//优势:可以实现多继承,比如继承BaseDao,然后再实现RunnableMyTask task = new MyTask();Thread thread2 = new Thread(task);thread2.start();//方式3:匿名内部类new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i);}}}).start();}}//方式1
class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i);}}
}//方式2
//优势:可以实现多继承,比如继承BaseDao,然后再实现Runnable
class MyTask implements Runnable {@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i);}}
}
1.4.3,Thread
常见方法
-
构造函数:
-
- Thread(): 创建新的Thread对象
- Thread(String threadname): 创建线程并指定线程实例名
- Thread(Runnable target): 指定创建线程的目标对象,它实现了Runnable接口中的run方法
- Thread(Runnable target, String name): 创建新的Thread对象
-
void start(): 启动线程,并执行对象的run()方法
-
run(): 线程在被调度时执行的操作
-
String getName(): 返回线程的名称
-
**void setName(String name)😗*设置该线程名称
-
static Thread currentThread(): 返回当前线程。在Thread子类中就是this,通常用于主线程和Runnable实现类
-
static void yield(): 线程让步
-
- 暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程
- 若队列中没有同优先级的线程,忽略此方法
-
join() : 当某个程序执行流中调用其他线程的 join() 方法时, 调用线程将被阻塞,直到 join() 方法加入的 join 线程执行完为止
-
static void sleep(long millis): (指定时间:毫秒) 令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队。
-
stop(): 强制线程生命期结束,不推荐使用
-
boolean isAlive(): 返回boolean,判断线程是否还活着
1.4.4,sleep()
方法
指定线程休眠的时间,单位毫秒,让出cpu时间片,其他线程可以抢占时间片
public class MyTask implements Runnable {@Overridepublic void run() {for (int i = 1; i <= 100; i++) {if (i % 2 == 0) {//Thread.currentThread().getName():得到线程的名字System.out.println(Thread.currentThread().getName() + "\t" + i);try {Thread.sleep(1000);Thread.yield();} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
}
1.4.5,线程优先级
-
线程的优先级等级
-
- MAX_PRIORITY: 10
- MIN _PRIORITY: 1
- NORM_PRIORITY: 5
public static void main(String[] args) {MyTask myTask = new MyTask();Thread thread1 = new Thread(myTask, "t1");thread1.setPriority(Thread.MIN_PRIORITY);thread1.start();Thread thread2 = new Thread(myTask, "t2");thread1.setPriority(Thread.MAX_PRIORITY);thread2.start();}
1.4.6,守护线程
- 其他线程都执行结束,守护线程自动结束
- 守护启动子线程,也是守护线程
- 守护线程的语法
thread.(*setDaemon(true)*
设置守护线程
public class Test2 {public static void main(String[] args) {MyThread myThread1 = new MyThread();
// myThread1.setDaemon(true);myThread1.start(); //守护线程, gc线程,jvm线程结束gc会自动结束JOptionPane.showMessageDialog(null, "是否确认向下执行...."); //主线程进入IO阻塞System.out.println("main over");}}class MyThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("a");}}
}
1.4.7,线程合并
案例:
public class Test1 {/*** CountDownLatch:可以实现相同的效果* @param args*/public static void main(String[] args) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i);try {Thread.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});t1.start();try {t1.join();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName() + " main orver");}}
1.4.8,线程退出
-
stop()
:不推荐,线程退出方式粗暴,不管线程正在执行的任务,直接退出,可能丢失数据。public class Test1 {public static void main(String[] args) {Thread t1 = new Thread(new MyTask());t1.start();Scanner in = new Scanner(System.in);System.out.println("输入1/0:0表示退出");int i = in.nextInt(); ///主线程进入IO阻塞if (i == 0) {t1.stop();}System.out.println("main over");}static class MyTask implements Runnable {@Overridepublic void run() {while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}}}} }
-
中断信号
interrupt
-
interrupt():发送中断信号(true)
-
- 如果线程在阻塞状态,比如sleep(),join(),wait(),这时接收到中断信号会抛出一个异常InterruptException,同时中断信号清除(false)
- 只是发送信号,不会对线程产生影响
-
**static interrupted():**得到中断信号(true),然后把中断信号设置成false
-
**isInterrupted():**得到中断信号,不会清除中断信号
public class Test1 {public static void main(String[] args) {Thread t1 = new Thread(new MyTask());t1.start();JOptionPane.showMessageDialog(null, "是否确认向下执行...."); //主线程进入IO阻塞t1.interrupt(); //发送中断信号给t1System.out.println("main over");}static class MyTask implements Runnable {@Overridepublic void run() {while (true) {System.out.println("a");try {Thread.sleep(500000);} catch (InterruptedException e) {System.out.println("bbbbbbbbbbbbbbb");e.printStackTrace();Thread.currentThread().interrupt(); //再次发送中断信号,中断信号发给阻塞线程,抛出Interrupt异常,中断信号清除 // throw new RuntimeException(e);}//得到中断信号,优雅的退出if (Thread.interrupted()) {break;}}}} }
-
📢 1.5,线程的生命周期
1.5.1,线程的调度与时间片
由于 CPU 的计算频率非常高,每秒计算数十亿次,于是,可以将 CPU 的时间从毫秒的维度进行分段,每一小段叫做一个 CPU 时间片。不同的操作系统、不同的处理器,线程的 CPU 时间片长度都不同。假定操作系统的线程一个时间片的时间长度为 20 毫秒(比如 Windows XP),在一个 2GHz 的 CPU 上,那么一个时间片可以进行计算的次数是: 20 亿/(1000/20) =4 千万次,也就是说,一个时间片内的计算量是非常巨大的。 目前操作系统中主流的线程调度方式大都是:基于 CPU 时间片方式进行线程调度。线程只有得到 CPU 时间片,才能执行指令,处于执行状态;没有得到时间片的线程,处于就绪状态,等待系统分配下一个 CPU 时间片。由于时间片非常短,在各个线程之间快速地切换,表现出来特征是很多个线程在“同时执行”或者“并发执行”。线程的调度模型,目前主要分为两种调度模型:分时调度模型、抢占式调度模型。
(1)分时调度模型——系统平均分配 CPU 的时间片,所有线程轮流占用 CPU。分时调度模型在时间片调度的分配上,所有线程人人平等。
下图就是一个分时调度的简单例子:三个线程,轮流得到 CPU 时间片;一个线程执行时,另外两个线程处于就绪状态
(2)抢占式调度模型——系统按照线程优先级分配 CPU 时间片。优先级高的线程,优先分配 CPU 时间片;如果所有的就绪线程的优先级相同,那么会随机选择一个;优先级高的线程获取的 CPU 时间片相对多一些。 由于目前大部分操作系统都是使用抢占式调度模型进行线程调度。 Java 的线程管理和调度是委托给了操作系统完成的,与之相对应, Java 的线程调度也是使用抢占式调度模型。
1.5.2,线程状态
操作系统,线程的状态
java的线程状态
得到java的线程状态
public Thread.State getState(); //返回当前线程的执行状态,一个枚举类型值
Thread.State
是一个内部枚举类,定义了6个枚举常量,分别代表Java线程的6种抓过你太,具体如下:
public static enum State {NEW, //新建RUNNABLE, //可执行:包含操作系统的就绪、运行两种状态BLOCKED, //阻塞 -> 操作系统线程中的阻塞WAITING, //等待 -> 操作系统线程中的阻塞TIMED_WAITING, //计时等待 -> 操作系统线程中的阻塞TERMINATED; //终止}
在Thread.State
定义的6中状态中,有四种是比较常见的状态,他们是:NEW
状态,RUNNABLE
状态,TERMINATED
状态,TIMED_WAITING
状态。
接下来,将线程的6种状态以及各种状态的进入条件,做个总结:
-
NEW
状态:通过new Thread(...)
已经创建线程,但尚未调用start()
启动线程,该线程处于NEW
(新建)状态。虽然前面介绍了4种创建线程,但是其中的其他三种方式,本质上都是通过new Thread()
创建的线程,仅仅是创建了不同的target执行目标示例(如Runnable
实例)。 -
RUNNABLE
状态:Java 把就绪(Ready)和 执行(Running)两种状态合并为一种状态:可执行(RUNNABLE)状态(或者可运行状态)。调用了线程的start()
实例方法后,线程就处于就绪状态了;此线程获取到CPU时间片后,开始执行run()
方法种的业务代码,线程处于执行状态。-
就绪状态:就绪状态仅仅表示线程具备运行资格,如果没有被操作系统的调度程序挑选中,线程就永远是就绪状态;当前线程进入就绪状态的条件,大致包括以下几种:
- 调用线程的
start()
方法,此线程进入就绪状态。 - 当前线程的执行时间片用完。
- 线程睡眠(sleep)操作结束。
- 对其他线程合入(join)操作结束。
- 等待用户输入结束。
- 线程争抢到对象锁(Object Monitor)。
- 当前线程调用了
yield()
方法,让出CPU执行权限。
- 调用线程的
-
执行状态:线程调度程序从就绪状态的线程中选择一个线程,作为当前线程时线程所处的状态。这也是线程进入执行状态的唯一方式。
-
BLOCKED 状态: 处于阻塞(BLOCKED)状态的线程并不会占用CPU资源,以下情况会让线程进入阻塞状态:
- 线程等待获取锁 :等待获取一个锁,而该锁被其他线程持有,则该线程进入阻塞状态。当其他线程释放了该锁,并且线程调度器允许该线程持有该锁时,该线程退出阻塞状态。
- IO 阻塞:线程发起了一个阻塞式 IO 操作后,如果不具备 IO 操作的条件,线程会进入阻塞状态。 IO 包括磁盘 IO、 网络 IO 等。 IO 阻塞的一个简单例子:线程等待用户输入内容后继续执行。
-
WAITING 状态:处于 WAITING(无限期等待)状态的线程不会被分配 CPU 时间片,需要被其他线程显式地唤醒,才会进入就绪状态。线程调用以下 3 种方法,会让自己进入无限等待状态:
- Object.wait() 方法,对应的唤醒方式为: Object.notify() / Object.notifyAll()。
- Thread.join() 方法,对应的唤醒方式为:被合入的线程执行完毕。
- LockSupport.park() 方法,对应的唤醒方式为: LockSupport.unpark(Thread)。
-
TIMED_WAITING 状态:处于 TIMED_WAITING(限时等待)状态的线程不会被分配 CPU 时间片,如果指定时间之内没有被唤醒,限时等待的线程会被系统自动唤醒,进入就绪状态。以下 3 个方法会让线程进入限时等待状态:
- Thread.sleep(time) 方法,对应的唤醒方式为: sleep 睡眠时间结束。
- Object.wait(time) 方 法 , 对 应 的 唤 醒 方 式 为 : 调 用 Object.notify() /Object.notifyAll()去主动唤醒,或者限时结束。
- LockSupport.parkNanos(time)/parkUntil(time) 方法,对应的唤醒方式为:线程调用配套的 LockSupport.unpark(Thread)方法结束,或者线程停止(park)时限结束。
进入 BLOCKED 状态、 WAITING 状态、 TIMED_WAITING 状态的线程都会让出 CPU 的使用权;另外,等待或者阻塞状态的线程被唤醒后,进入 Ready 状态,需要重新获取时间片才能接着运行。
-
TERMINATED 状态:线程结束任务之后,将会正常进入 TERMINATED(死亡)状态;或者说在线程执行过程中发生了异常(而没有被处理),也会导致线程进入死亡状态。
-
1.5.3,多线程自增 i++ 和线程执行原理
4个线程自增一个堆(共享的)里的对象的值
public class Test {private int i =0;public void f1() {i++;}
}
i++的反编译结果
javap -c Test.class
线程产生时 ,为每个线程的一个虚拟机栈分配1M内存
-Xss128K:指定没有线程的栈大小是128K
自增类:
public class Plus {private int amount = 0;public void selfPlus() {amount ++;}public int getAmount() {return amount;}}
自增任务类
public class PlusTask implements Runnable {private Plus plus;public PlusTask() {}public PlusTask(Plus plus) {this.plus = plus;}@Overridepublic void run() {for (int i = 0; i < 100000000; i++) {plus.selfPlus();}}}
测试
public static void main(String[] args) throws InterruptedException {Plus plus = new Plus();PlusTask plusTask = new PlusTask(plus);Thread t1 = new Thread(plusTask);Thread t2 = new Thread(plusTask);Thread t3 = new Thread(plusTask);Thread t4 = new Thread(plusTask);t1.start();t2.start();t3.start();t4.start();t1.join();t2.join();t3.join();t4.join();System.out.println("实际的值 = " + plus.getAmount());}
相关文章:

⛳ Java多线程 一,线程基础
线程基础 ⛳ Java多线程 一,线程基础🐾 一,线程基础💭 1.1,什么是程序,进程,线程🏭 1.2,什么是并行和并发👣 1.3,线程使用的场景🎨 1.…...

【iOS】多线程 锁问题总结
文章目录 前言1. 你理解的多线程优点缺点 2. atomic 和 nonatomic 的区别及其作用3. GCD的队列类型 - 三种队列类型4. GCD的死锁问题5. 多线程之间的区别和联系6. 进程和线程?进程间的通信方式线程间的通信方式 6. iOS的线程安全手段如何保证 前言 iOS 锁和多线程的…...

Pytorch深度学习-----神经网络之池化层用法详解及其最大池化的使用
系列文章目录 PyTorch深度学习——Anaconda和PyTorch安装 Pytorch深度学习-----数据模块Dataset类 Pytorch深度学习------TensorBoard的使用 Pytorch深度学习------Torchvision中Transforms的使用(ToTensor,Normalize,Resize ,Co…...

Docker啥是数据持久化?
文章目录 数据持久化数据卷相关命令创建读写数据卷创建只读数据卷数据卷共享数据卷容器实现数据卷共享nginx实现数据卷共享nfs总结 Dockerfile持久化Dockerfile方式docker run总结 数据持久化 在容器层的 UnionFS(联合文件系统)中对文件/目录的任何修…...
CGAL 线段简化算法(2D)
文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 线段简化是指:在减少一组折线中顶点数量的同时,尽可能保持整体形状的过程。CGAL中提供了一种迭代算法:通过从一条折线上移除顶点 q q q,迭代地将边 ( p , q...

在CentOS 7上挂载硬盘到系统的步骤及操作
目录 1:查询未挂载硬盘2:创建挂载目录3:检查磁盘是否被分区4:格式化硬盘5:挂载目录6:检查挂载状态7:设置开机自动挂载总结: 本文介绍了在CentOS 7上挂载硬盘到系统的详细步骤。通过确…...

螺旋矩阵(JS)
螺旋矩阵 题目 给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1: 输入:n 3 输出:[[1,2,3],[8,9,4],[7,6,5]]示例 2: 输入ÿ…...
C#常用数学插值法
目录 1、分段线性插值 2、三次样条插值 3、拉格朗日插值 (1)一元全区间不等距插值 (2)一元全区间等距插值 4、埃尔米特插值 (1)埃尔米特不等距插值 (2)埃尔米特等距插值 1、…...

ELK日志管理平台架构和使用说明
一、部署架构 二、服务注册 2.1 日志解析服务 服务名:日志解析服务(Logstash) 服务默认端口:9600 2.2 日志查询服务 服务名:日志查询服务(Kibana) 服务默认端口:5601 三、对接…...

抖音短视频seo矩阵系统源码开发部署技术分享
抖音短视频的SEO矩阵系统是一个非常重要的部分,它可以帮助视频更好地被搜索引擎识别和推荐。以下是一些关于开发和部署抖音短视频SEO矩阵系统的技术分享: 一、 抖音短视频SEO矩阵系统的技术分享: 关键词研究:在开发抖音短视频SEO矩…...
docker 部署一个单节点的rocketmq
拉取镜像 sudo docker pull rocketmqinc/rocketmq创建数据挂载目录 mkdir -p /docker/rocketmq/data/namesrv/logs mkdir -p /docker/rocketmq/data/namesrv/store mkdir -p /docker/rocketmq/data/broker/logs mkdir -p /docker/rocketmq/data/broker/store /docker/…...
MySQL优化
目录 一. 优化 SQL 查询语句 1.1. 分析慢查询日志 1.2. 优化 SQL 查询语句的性能 1.2.1 优化查询中的索引 1.2.2 减少表的连接(join) 1.2.3 优化查询语句中的过滤条件 1.2.4 避免使用SELECT * 1.2.5 优化存储过程和函数 1.2.6 使用缓存 二. 优化表结构…...

【C++】总结9
文章目录 C从源代码到可执行程序经过什么步骤静态链接和动态链接类的对象存储空间C的内存分区内存池在成员函数中调用delete this会出现什么问题?如果在类的析构函数中调用delete this,会发生什么? C从源代码到可执行程序经过什么步骤 预处理…...

C++报错 XX does not name a type;field `XX’ has incomplete type解决方案
C报错 XX does not name a type;field XX’ has incomplete type解决方案 两个C编译错误及解决办法–does not name a type和field XX’ has incomplete type 编译错误一:XX does not name a type 编译错误二:field XX’ has incomplete t…...

28.利用fminsearch、fminunc 求解最大利润问题(matlab程序)
1.简述 1.无约束(无条件)的最优化 fminunc函数 : - 可用于任意函数求最小值 - 统一求最小值问题 - 如求最大值问题: >对函数取相反数而变成求最小值问题,最后把函数值取反即为函数的最大值。 使用格式如下 1.必须预先把函数存…...

图像 检测 - FCOS: Fully Convolutional One-Stage Object Detection (ICCV 2019)
FCOS: Fully Convolutional One-Stage Object Detection - 全卷积一阶段目标检测(ICCV 2019) 摘要1. 引言2. 相关工作3. 我们的方法3.1 全卷积一阶目标检测器3.2 FCOS的FPN多级预测3.3 FCOS中心度 4. 实验4.1 消融研究4.1.1 FPN多级预测4.1.2 有无中心度…...

C# NDArray System.IO.FileLoadException报错原因分析
C# NDArray System.IO.FileLoadException 报错原因分析: 1.NuGet程序包版本有冲突 2.统一项目版本 1.打开解决方案NuGet程序包设置 2.查看是否有版本冲突 3.统一版本冲突...

快速响应,上门维修小程序让您享受无忧生活
随着科技的不断发展和智能手机的普及,上门维修小程序成为了现代人生活中越来越重要的一部分。上门维修小程序通过将维修服务与互联网相结合,为用户提供了更加便捷、高效的维修服务体验。下面将介绍上门维修小程序开发的优势。 提供便捷的预约方式&am…...

05、性能分析思路?
工具操作:包括压力工具、监控工具、剖析工具、调试工具。数值理解:包括上面工具中所有输出的数据。趋势分析、相关性分析、证据链分析:就是理解了工具产生的数值之后,还要把它们的逻辑关系想明白。这才是性能测试分析中最重要的一…...

【编程语言 · C语言 · calloc和realloc】
【编程语言 C语言 calloc和realloc】https://mp.weixin.qq.com/s?__bizMzg4NTE5MDAzOA&mid2247491544&idx1&sn72d8f9931cfa7ce7441a3248475ab619&chksmcfade321f8da6a374a5935bb46441a03a007c0589db6b8afa8c1991854d632a3201553e37b0b&payreadticketHGy…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...

免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...