传送门

分布式定时任务系列1:XXL-job安装

分布式定时任务系列2:XXL-job使用

分布式定时任务系列3:任务执行引擎设计

分布式定时任务系列4:任务执行引擎设计续

分布式定时任务系列5:XXL-job中blockingQueue的应用

分布式定时任务系列6:XXL-job触发日志过大引发的CPU告警

分布式定时任务系列7:XXL-job源码分析之任务触发

分布式定时任务系列8:XXL-job源码分析之远程调用

 分布式定时任务系列9:XXL-job路由策略

分布式定时任务系列10:XXL-job源码分析之路由策略

番外篇:从XXL-job路由策略的“服务容错“说起

分布式定时任务系列12:XXL-job的任务触发为什么是死循环?

Java并发编程实战1:java中的阻塞队列

定时任务都是通过"死循环"触发?

在前面一共分析过XXL-job的定时任务触发原理、JDK-Timer执行定时任务的原理:

  • 底层源码都是通过while(true)这种死循环写法来遍历任务的
  • 一个是分布式调度框架,更为重量级、一个是JDK提供的偏轻量级的调度工具

尽管2者定位不同,但是都选择了死循环这种方式来实现任务调度,说明while(true)一定是可行的、通用的设计方式。但是要问任务调度都是采用这种方式,那答案肯定是否定的。一来只分析了XXL-job与Timer的源码导致样本太少,二来接下来要分析的另一个任务调度工具,也的确不是通过死循环这种方式:它就是JDK提供的ScheduledExecutorService!

ScheduledExecutorService源码解析

ScheduledExecutorService是什么

ScheduledExecutorService 是Java并发框架中用于定时任务调度的核心接口,基于线程池实现,支持延迟任务执行和周期性任务调度,相比传统 Timer 类更高效、更灵活。 ‌

核心功能

提供schedulescheduleAtFixedRatescheduleWithFixedDelay等方法,可安排任务在指定延迟后执行一次,或按固定频率周期执行。支持任务并发执行,适用于需要定时轮询、消息推送等场景。 ‌

关键特性

  • 线程池管理‌:默认使用 ScheduledThreadPoolExecutor ,可设置核心线程数(如Executors.newScheduledThreadPool(1)),支持多任务并发执行 ‌
  • 任务调度策略‌:
    • schedule:延迟后执行一次任务
    • scheduleAtFixedRate:初始延迟后按固定频率重复执行(如每5秒执行一次)
    • scheduleWithFixedDelay:首次执行后等待固定延迟再执行(如首次执行后每10秒执行一次) ‌
  • 取消任务‌:可通过返回的Future对象取消未执行的任务 ‌

适用场景

  • 定时轮询数据库或第三方接口(如每5分钟检查数据更新)
  • 定时发送消息或推送通知(如每日定时邮件发送)
  • 周期性任务调度(如每2小时重启服务) ‌

ScheduledExecutorService的使用

ScheduledExecutorService类自jdk1.5才引入,作者是大名鼎鼎的Doug Lea(Java并发包juc的作者)。既然它开始工作的晚,自然离"退休"还早,现在一般推荐使用!

说到Doug Lea自然要推荐他与Joshua Bloch等合著的《Java并发编程实战》,见推荐书单。

看一下源码中给出的一个例子:

import static java.util.concurrent.TimeUnit .*;class BeeperControl {// 创建执行器实例,初始化1个执行线程private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);public void beepForAnHour() {final Runnable beeper = new Runnable() {public void run() {System.out.println("beep");}};// 固定频率周期性执行任务:每10s执行一次任务,发出"哗"声!final ScheduledFuture<?> beeperHandle = scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);// 延迟 delay 后执行一次任务:一次性任务,3600s(1小时)后"取消"任务        
scheduler.schedule(new Runnable() {public void run() {beeperHandle.cancel(true);}}, 60 * 60, SECONDS);}
}

可以写一个测试跑一下上面的例子,然后再用Timer改写上面的例子,分别执行会发现效果是一致的:

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;/*** @author * @date 2025/7/16*/
public class ScheduleTest {private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);public static void main(String[] args) {ScheduledExecutorServiceBeepForAnHour();timerBeepForAnHour();}/*** 使用ScheduledExecutorService实现定时任务*/public static void ScheduledExecutorServiceBeepForAnHour() {final Runnable beeper = new Runnable() {public void run() {System.out.println(new Date() + "ScheduledExecutorService for beep");}};final ScheduledFuture<?> beeperHandle = scheduler.scheduleAtFixedRate(beeper, 10, 10, TimeUnit.SECONDS);scheduler.schedule(new Runnable() {public void run() {beeperHandle.cancel(true);}}, 60 * 60, TimeUnit.SECONDS);}/*** 使用Timer实现实时任务*/public static void timerBeepForAnHour() {// 创建Timer执行器实例Timer timer = new Timer();// 执行任务:,发出"哗"声!TimerTask beeper = new TimerTask() {@Overridepublic void run() {System.out.println(new Date() + "Timer for beep");}};// 固定频率周期性执行任务:每10s执行一次任务,发出"哗"声!timer.scheduleAtFixedRate(beeper, 10, 10 * 1000);// 延迟 delay 后执行一次任务:一次性任务,3600s(1小时)后"取消"任务timer.schedule(new TimerTask() {@Overridepublic void run() {beeper.cancel();}}, 60 * 60 * 1000);}
}

上面例子要注意的是,timer的API里面的时间是毫秒,而ScheduledExecutorService是可以通过TimeUnit指定时间单位的。 

仅通过这个例子就简单的认为功能两者一样,那肯定缺乏说服力的。并且如果两个调度器一样,也有重复造轮子的嫌疑,所以再接着改写一下上面的例子:

  • 增加一个执行任务,执行器里面维持2个任务
  • 在任务里面将执行线程信息打印出来
  • 但同时将ScheduledExecutorService的执行线程数从1调整为2
public class ScheduleTest {// 创建ScheduledExecutorService 执行器private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);public static void main(String[] args) {scheduledExecutorServiceBeepForAnHour();timerBeepForAnHour();}/*** 使用ScheduledExecutorService实现定时任务*/public static void scheduledExecutorServiceBeepForAnHour() {// 任务1final Runnable beeper = new Runnable() {public void run() {System.out.println(Thread.currentThread().getName() + "," + new Date() + ", ScheduledExecutorService for beep1");}};// 任务2Runnable beeper2 = () -> {System.out.println(Thread.currentThread().getName() + "," + new Date() + ", ScheduledExecutorService for beep2");};// 添加第1个任务final ScheduledFuture<?> beeperHandle = scheduler.scheduleAtFixedRate(beeper, 10, 10, TimeUnit.SECONDS);// 添加第2个任务scheduler.scheduleAtFixedRate(beeper2, 10, 10, TimeUnit.SECONDS);scheduler.schedule(new Runnable() {public void run() {beeperHandle.cancel(true);}}, 60 * 60, TimeUnit.SECONDS);}/*** 使用Timer实现实时任务*/public static void timerBeepForAnHour() {// 创建Timer执行器实例Timer timer = new Timer();// 执行任务1:发出"哗"声!TimerTask beeper = new TimerTask() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "," + new Date() + ", Timer for beep1");}};执行任务2:TimerTask beeper2 = new TimerTask() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "," + new Date() + ", Timer for beep2");}};// 固定频率周期性执行任务:每10s执行一次任务,发出"哗"声!timer.scheduleAtFixedRate(beeper, 10, 10 * 1000);timer.scheduleAtFixedRate(beeper2, 10, 10 * 1000);// 延迟 delay 后执行一次任务:一次性任务,3600s(1小时)后"取消"任务timer.schedule(new TimerTask() {@Overridepublic void run() {beeper.cancel();}}, 60 * 60 * 1000);}
}

运行程序,打印结果:

Timer-0,Mon Jul 21 11:43:46 CST 2025, Timer for beep1
Timer-0,Mon Jul 21 11:43:46 CST 2025, Timer for beep2

pool-1-thread-2,Mon Jul 21 11:43:56 CST 2025, ScheduledExecutorService for beep2
pool-1-thread-1,Mon Jul 21 11:43:56 CST 2025, ScheduledExecutorService for beep1

Timer-0,Mon Jul 21 11:43:56 CST 2025, Timer for beep2
Timer-0,Mon Jul 21 11:43:56 CST 2025, Timer for beep1

pool-1-thread-1,Mon Jul 21 11:44:06 CST 2025, ScheduledExecutorService for beep1
Timer-0,Mon Jul 21 11:44:06 CST 2025, Timer for beep1
pool-1-thread-2,Mon Jul 21 11:44:06 CST 2025, ScheduledExecutorService for beep2
Timer-0,Mon Jul 21 11:44:06 CST 2025, Timer for beep2
pool-1-thread-2,Mon Jul 21 11:44:16 CST 2025, ScheduledExecutorService for beep2
pool-1-thread-1,Mon Jul 21 11:44:16 CST 2025, ScheduledExecutorService for beep1

上面截取了一部分打印结果,会发现对于ScheduledExecutorService来说,随着执行线程的增加,任务是可能会由不同的线程执行。但是Timer来说,它始终只会有一个线程来执行任务。由此我们推断两个类在执行执行上是不同的,再改写一下上面的例子:

  • 将任务阻塞50s,大于执行的同期10s
public class ScheduleTest {// 创建执行private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);public static void main(String[] args) {scheduledExecutorServiceBeepForAnHour();timerBeepForAnHour();}/*** 使用ScheduledExecutorService实现定时任务*/public static void scheduledExecutorServiceBeepForAnHour() {final Runnable beeper = new Runnable() {@SneakyThrowspublic void run() {// 阻塞任务1,50sTimeUnit.SECONDS.sleep(50);System.out.println(Thread.currentThread().getName() + "," + new Date() + ", ScheduledExecutorService for beep1");}};Runnable beeper2 = () -> {System.out.println(Thread.currentThread().getName() + "," + new Date() + ", ScheduledExecutorService for beep2");};// 添加第1个任务final ScheduledFuture<?> beeperHandle = scheduler.scheduleAtFixedRate(beeper, 10, 10, TimeUnit.SECONDS);// 添加第2个任务scheduler.scheduleAtFixedRate(beeper2, 10, 10, TimeUnit.SECONDS);scheduler.schedule(new Runnable() {public void run() {beeperHandle.cancel(true);}}, 60 * 60, TimeUnit.SECONDS);}/*** 使用Timer实现实时任务*/public static void timerBeepForAnHour() {// 创建Timer执行器实例Timer timer = new Timer();// 执行任务:,发出"哗"声!TimerTask beeper = new TimerTask() {@SneakyThrows@Overridepublic void run() {// 阻塞任务1,50sTimeUnit.SECONDS.sleep(50);System.out.println(Thread.currentThread().getName() + "," + new Date() + ", Timer for beep1");}};TimerTask beeper2 = new TimerTask() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "," + new Date() + ", Timer for beep2");}};// 固定频率周期性执行任务:每10s执行一次任务,发出"哗"声!timer.scheduleAtFixedRate(beeper, 10, 10 * 1000);timer.scheduleAtFixedRate(beeper2, 10, 10 * 1000);// 延迟 delay 后执行一次任务:一次性任务,3600s(1小时)后"取消"任务timer.schedule(new TimerTask() {@Overridepublic void run() {beeper.cancel();}}, 60 * 60 * 1000);}
}

 运行程序,打印结果:

pool-1-thread-2,Mon Jul 21 12:20:02 CST 2025, ScheduledExecutorService for beep2
pool-1-thread-2,Mon Jul 21 12:20:12 CST 2025, ScheduledExecutorService for beep2
pool-1-thread-2,Mon Jul 21 12:20:22 CST 2025, ScheduledExecutorService for beep2
pool-1-thread-2,Mon Jul 21 12:20:32 CST 2025, ScheduledExecutorService for beep2
pool-1-thread-2,Mon Jul 21 12:20:42 CST 2025, ScheduledExecutorService for beep2
Timer-0,Mon Jul 21 12:20:42 CST 2025, Timer for beep1
Timer-0,Mon Jul 21 12:20:42 CST 2025, Timer for beep2
Timer-0,Mon Jul 21 12:20:42 CST 2025, Timer for beep2

pool-1-thread-2,Mon Jul 21 12:20:52 CST 2025, ScheduledExecutorService for beep2
pool-1-thread-1,Mon Jul 21 12:20:52 CST 2025, ScheduledExecutorService for beep1

从上面的输出观察到的现象:

  • 对于Timer来说,是单线程执行的,一旦执行线程被阻塞,所有任务都会被阻塞至于阻塞解除才会被重新执行(是否补偿取决于不同的API) 
  • 对于ScheduledExecutorService来说,是多线程执行的,单个线程的阻塞不会造成其它任务的执行,理论上执行效率更高

ScheduledExecutorService与Timer对比

特性TimerScheduledExecutorService
引入版本Java 1.3(早期)Java 5(java.util.concurrent包)
所属包java.util.Timerjava.util.concurrent.ScheduledExecutorService
核心功能单线程定时任务调度多线程任务调度(支持线程池)

 从构造方法看类结构

 为了体现ScheduledExecutorService执行器底层用的线程池,我们大费周章的写了好几个例子来验证推断,其实通过它的构造方法也看出来:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);// 创建调度线程池
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);}// 创建调度线程池,这里会super通过调用线程池创建
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());}// 标准线程池
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}/*** Creates a new {@code ThreadPoolExecutor} with the given initial* parameters.** @param corePoolSize the number of threads to keep in the pool, even*        if they are idle, unless {@code allowCoreThreadTimeOut} is set* @param maximumPoolSize the maximum number of threads to allow in the*        pool* @param keepAliveTime when the number of threads is greater than*        the core, this is the maximum time that excess idle threads*        will wait for new tasks before terminating.* @param unit the time unit for the {@code keepAliveTime} argument* @param workQueue the queue to use for holding tasks before they are*        executed.  This queue will hold only the {@code Runnable}*        tasks submitted by the {@code execute} method.* @param threadFactory the factory to use when the executor*        creates a new thread* @param handler the handler to use when execution is blocked*        because the thread bounds and queue capacities are reached* @throws IllegalArgumentException if one of the following holds:<br>*         {@code corePoolSize < 0}<br>*         {@code keepAliveTime < 0}<br>*         {@code maximumPoolSize <= 0}<br>*         {@code maximumPoolSize < corePoolSize}* @throws NullPointerException if {@code workQueue}*         or {@code threadFactory} or {@code handler} is null*/public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.acc = System.getSecurityManager() == null ?null :AccessController.getContext();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}

由于源码里面涉及到线程池代码比较,这里不就完整的贴出来了,只展示相关重要的几个类:

首先创建线程池:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
 Executors介绍

Executors 的核心作用是封装线程池的创建逻辑,通过不同的静态方法提供以下几种线程池类型:

  • 固定大小的线程池(Fixed Thread Pool)
  • 可缓存的线程池(Cached Thread Pool)
  • 单线程的线程池(Single Thread Pool)
  • 周期性任务调度线程池(Scheduled Thread Pool)

这些线程池分别适用于不同的场景,比如任务数量固定、任务数量不确定、需要单线程执行、或需要定时执行任务等。

 Executors 提供的常用静态方法
方法说明适用场景
newFixedThreadPool(int nThreads)创建一个固定大小的线程池,线程数始终为 nThreads任务数量固定、资源有限的场景
newCachedThreadPool()创建一个可缓存的线程池,线程数可根据任务动态调整任务数量不确定、需要快速响应的场景
newSingleThreadExecutor()创建一个单线程的线程池,保证任务按顺序执行需要串行执行任务的场景
newScheduledThreadPool(int corePoolSize)创建一个支持定时任务调度的线程池需要周期性或延迟执行任务的场景
newWorkStealingPool(int parallelism)创建一个基于工作窃取算法的线程池(Java 8+)多核 CPU 下并行任务处理

而ScheduledThreadPoolExecutor与ScheduledExecutorService是接口->实现关系,而能创建线程池的原因在于ScheduledThreadPoolExecutor与ThreadPoolExecutor的继承关系:

public class ScheduledThreadPoolExecutorextends ThreadPoolExecutorimplements ScheduledExecutorService {// 具体方法略,重点明确类关系...
}

 类图

直接上类图看看:

 

至此得到了ScheduledExecutorService类的完整类图,其中:

  • 通过Executors获取线程池ScheduledThreadPoolExecutor
  • ScheduledThreadPoolExecutor有两个内部类:DelayedWorkQueue、ScheduledFutureTask
  • ScheduledFutureTask封装了FutureTask,可以获取任务执行结果、任务取消、设置任务周期
  • DelayedWorkQueue封装了延迟队列,提供了任务管理的方法

定时器-任务线程启动

通过线程池之后,任务的启动就不用定时器自动管理了,而是委托给线程池来管理了,这里就不展示开,有兴趣可以看看之前关于线程池源码的分析《深入解析Java线程池-CSDN博客》,同理定时任务执行也不用定时器来触发了

定时任务执行

谈到定时任务的触发,就又回到我们开篇的疑问了,是不是所有的调度器都是通过类似while(true)这种"死循环"策略?答案是"否定"的,至少从ScheduledExecutorService代码来看不是这样的,它的线程、任务的管理都是通过各种池来实现的,这样非常方便。但是线程执行任务完成之后,对于周期性的任务,还是需要扩展任务、队列来完成,比如下面添加任务的代码:

// 添加周期性任务
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit) {if (command == null || unit == null)throw new NullPointerException();if (period <= 0)throw new IllegalArgumentException();ScheduledFutureTask<Void> sft =new ScheduledFutureTask<Void>(command,null,triggerTime(initialDelay, unit),unit.toNanos(period));// 封装任务,里面存储了任务周期period字段RunnableScheduledFuture<Void> t = decorateTask(command, sft);sft.outerTask = t;delayedExecute(t);return t;}private class ScheduledFutureTask<V>extends FutureTask<V> implements RunnableScheduledFuture<V> {/** Sequence number to break ties FIFO */private final long sequenceNumber;/** The time the task is enabled to execute in nanoTime units */private long time;// 任务周期private final long period;
}

再继续看延迟执行方法:

private void delayedExecute(RunnableScheduledFuture<?> task) {if (isShutdown())reject(task);else {// 重点是这个,添加任务到队列里面super.getQueue().add(task);if (isShutdown() &&!canRunInCurrentRunState(task.isPeriodic()) &&remove(task))task.cancel(false);else// 添加任务成功,调用此方法:用于确保线程池中至少有一个工作线程在运行ensurePrestart();}}

 而任务执行完成后,如果是同期性任务则会重新设置执行时间来达到周期性执行效果:

public void run() {// 获取是否周期性任务标志boolean periodic = isPeriodic();if (!canRunInCurrentRunState(periodic))cancel(false);// 如果不是周期性任务,则直接执行else if (!periodic)ScheduledFutureTask.super.run();// 如果是周期性任务,则先重置执行状态&设置下次执行时间再执行任务else if (ScheduledFutureTask.super.runAndReset()) {setNextRunTime();reExecutePeriodic(outerTask);}}

加引号的"列循环"

谈到定时任务的触发,就又回到我们开篇的疑问了,是不是所有的调度器都是通过类似while(true)这种"死循环"策略?答案是"否定"的

在前面回答这个问题时,"否定"加了引号的。严格意义来说,线程池底层的代码其实也是一种死循环,它通过自旋的方式来获取任务:

private Runnable getTask() {boolean timedOut = false; // Did the last poll() time out?// 没有条件的for循环,会一直持有CPU,这种方式称为自旋for (;;) {int c = ctl.get();int rs = runStateOf(c);// Check if queue empty only if necessary.if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {decrementWorkerCount();return null;}int wc = workerCountOf(c);// Are workers subject to culling?boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;if ((wc > maximumPoolSize || (timed && timedOut))&& (wc > 1 || workQueue.isEmpty())) {if (compareAndDecrementWorkerCount(c))return null;continue;}try {Runnable r = timed ?workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :workQueue.take();if (r != null)return r;timedOut = true;} catch (InterruptedException retry) {timedOut = false;}}}

 由于里面涉及大量的JAVA并发编程,就不展开了,可以自行看看源码及相关书籍。

推荐书单

《Java并发编程实战》:力荐!五星!

个人肤浅的认为是看过写的最好的一本Java并发编码方面的书,初看惊为天人,值的读好几遍!不过缺点就是刚看不容易懂也容易忘,隔段时间又要重头看起。而且理论偏多代码例子较少,有一定的阅读门槛

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flutter基础(前端教程①③-单例)

现实类比&#xff1a;公司打印机假设你们公司有一台共享打印机&#xff1a;非单例&#xff08;重复创建&#xff09;&#xff1a;每个员工都自己买一台打印机放在工位上结果&#xff1a;浪费钱&#xff0c;占空间&#xff0c;难维护单例&#xff08;唯一实例&#xff09;&#…

力扣刷题 -- 965.单值二叉树

题目示例&#xff1a; 思路分析代码实现 bool isUnivalTree(struct TreeNode* root) {if(rootNULL){return true;}if(root->left && root->val ! root->left->val){return false;}if(root->right && root->val ! root->right->val){re…

uni-api交互反馈组件(showToast)的用法

欢迎来到我的UniApp技术专栏&#xff01;&#x1f389; 在这里&#xff0c;我将与大家分享关于UniApp开发的实用技巧、最佳实践和项目经验。 专栏特色&#xff1a; &#x1f4f1; 跨平台开发一站式解决方案 &#x1f680; 从入门到精通的完整学习路径 &#x1f4a1; 实战项目经…

借助它,在Web3投资赛道抢占先机

随着互联网技术的飞速发展&#xff0c;Web3的概念逐渐成为科技圈和投资界的热门话题。Web3代表着下一代互联网的发展方向&#xff0c;它强调去中心化、用户主权和数据隐私保护。在这一新兴领域&#xff0c;如何借助Web3技术抢占投资先机&#xff0c;成为许多投资者关注的焦点。…

验证大语言模型不会算数但可以编写算数的程序

摘要&#xff1a;本文通过几个实例测试了大语言模型在数学计算、排序、统计等方面的能力。结果显示&#xff0c;对于简单字符统计、排序等任务&#xff0c;大模型能正确生成实现代码&#xff0c;但当数据区分度降低时容易出错。在计算学生分数排名任务中&#xff0c;大模型生成…

概率论与数理统计(八)

参数估计 通过取样本&#xff0c;并用样本构造函数&#xff0c;达成估计分布函数参数的目的 矩估计法 本质&#xff1a;用样本的各阶矩代替总体的各阶矩&#xff0c;即取&#xff1a; E(X)X‾1n∑iXiE(X2)1n∑iXi2E(X)\overline{X}\dfrac{1}{n}\sum_i X_i\\ E(X^2)\dfrac{1}…

服务器后台崩溃的原因

当我们双十一活动零点拼命刷新却卡在支付完页面&#xff0c;游戏页面等不进去&#xff0c;公司系统瘫痪全体员工干瞪眼&#xff0c;服务器崩溃绝对是数字时代中的酷刑&#xff01;那服务器为什么会说崩就崩&#xff0c;用户对于这种情况该如何进行避雷呢&#xff1f;服务器主要…

线程池与ThreadPoolExecutor源码解析(上)

一、线程池线程池&#xff08;ThreadPool&#xff09;是一种线程复用的机制。它维护着若干个线程&#xff0c;任务来了就复用这些线程去执行&#xff0c;任务做完线程不会销毁&#xff0c;而是回到池中等待下一个任务。为什么要用线程池&#xff1f;降低资源消耗&#xff1a;避…

Linux内核IP分片重组机制剖析:高效与安全的艺术

在IP网络通信中,当数据包超过MTU限制时,路由器会将其拆分为多个分片。这些分片到达目标主机后,内核必须高效、安全地重组原始数据包。Linux内核的net/ipv4/inet_fragment.c实现了一套精妙的分片管理框架,完美平衡了性能和安全性需求。本文将深入剖析其设计哲学与关键技术。…

相机模型和对极几何

一、相机模型 1.针孔相机模型-外参矩阵 1.世界坐标系到相机坐标系 世界坐标系&#xff1a;可以定义空间中任意一个位置&#xff0c;原点位置三个坐标轴方向坐标系姿态&#xff08;X,Y,Z&#xff09;相机坐标系&#xff1a;定义在相机上&#xff0c;原点是相机中心&#xff0c;z…

Git 常用命令与操作步骤

以下是 Git 常用命令与操作步骤 的整理&#xff0c;涵盖日常开发中最核心的场景&#xff0c;适合快速查阅和上手&#xff1a;1. 初始化与克隆仓库操作命令本地初始化仓库git init克隆远程仓库git clone <仓库URL> &#xff08;如 git clone https://gitlab.com/user/repo…

Leetcode-.283移动零

class Solution:def moveZeroes(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""pos0for i in range(len(nums)):if nums[i]!0:nums[pos],nums[i]nums[i],nums[pos]pos1本题运用双指针来写&…

在React中做过哪些性能优化?

1. 使用 React.memo 进行组件优化 问题:当父组件重新渲染时,子组件也会重新渲染,即使它的 props 没有变化。 解决方案:使用 React.memo 包裹子组件,让其只在 props 变化时才重新渲染。 const MyComponent = React.memo((props) => {// 子组件代码 }); 2. 使用 useCa…

安装docker可视化工具 Portainer中文版(ubuntu上演示,所有docker通用) 支持控制各种容器,容器操作简单化 降低容器门槛

以下有免费的4090云主机提供ubuntu22.04系统的其他入门实践操作 地址&#xff1a;星宇科技 | GPU服务器 高性能云主机 云服务器-登录 相关兑换码星宇社区---4090算力卡免费体验、共享开发社区-CSDN博客 兑换码要是过期了&#xff0c;可以私信我获取最新兑换码&#xff01;&a…

ansible批量部署zabbix客户端

✅ansible编写剧本步骤 1️⃣创建roles目录结构2️⃣在group_vars/all/main.yml中定义变量列表3️⃣在tasks目录下编写tasks任务4️⃣在files目录下准备部署文件5️⃣在templates目录下创建j2模板文件6️⃣在handlers目录下编写handlers7️⃣在roles目录下编写主playbook8️⃣运…

蚂蚁数科AI数据产业基地正式投产,携手苏州推进AI产业落地

近日&#xff0c;蚂蚁数科AI数据产业基地在太仓智汇谷科技创新园正式投产。该基地作为苏州市首个AI数据产业基地&#xff0c;旨在通过跨行业人才与前沿技术&#xff0c;为长三角制造业、金融、医疗等领域的大模型落地提供场景化、高质量的训练数据支撑。数据被视为AI学习的核心…

计算机的网络体系及协议模型介绍

目录 1、网络协议介绍 1.1、定义 1.2、基本作用 1.3、协议的主要内容 2、网络协议分层 2.1、协议分层原因 2.2、网络协议分层的缺点 2.3、OSI协议和TCP/IP协议的联系 3、TCP/IP 协议族 3.1、定义介绍 3.2、组成 1、应用层 2、运输层 3、网络层 3.3、底层流程 4、…

密码管理安全防御

密码管理是信息安全的核心环节,其目标是通过规范密码的生成、存储、传输、验证和生命周期管理,防止未授权访问,保护用户账号和系统资源的安全。以下从核心原则、技术实践、常见问题及解决方案等方面详细说明: 一、密码管理的核心原则 密码管理需遵循“安全性”与“可用性…

Java异步日志系统性能优化实践指南:基于Log4j2异步Appender与Disruptor

Java异步日志系统性能优化实践指南&#xff1a;基于Log4j2异步Appender与Disruptor 一、技术背景与应用场景 在高并发的后端应用中&#xff0c;日志记录往往成为性能瓶颈之一。同步写日志会阻塞业务线程&#xff0c;导致响应延迟&#xff1b;而简单的异步队列实现又可能出现积压…

Mybatis07-缓存

一、缓存机制的原理计算机每次从mysql中执行sql语句&#xff0c;都是内存与硬盘的通信&#xff0c;对计算机来说&#xff0c;影响效率。因此使用缓存机制。1-1、MyBatis 的缓存机制&#xff1a;执行 DQL&#xff08;select 语句&#xff09;的时候&#xff0c;将查询结果放到缓…