Netty源码分析---startThread方法详解

Netty源码分析:NioEventLoop启动以及其IO操作和Task任务的处理 Netty源码分析:NioEventLoop类的execute、startThread、run方法在上篇博文分析服务端启动的过程中,我们遇到了如下的代码片段, if (eventLoop.inEventLoop()) {//判断当前线程是否为该EventLoop中拥有的线程,如果是,则直接注册,如果不是,则添加一个任务到该线程中 register 阅读详情

startThread() 方法完整解析

一、方法调用链

execute(task)
    ↓
startThread()
    ↓
doStartThread()
    ↓
executor.execute(runnable)
    ↓
创建并启动 Thread
    ↓
执行 run() 方法(死循环)

二、startThread() 方法源码

private void startThread() {
    // 1. 检查状态:只有在未启动状态才会启动
    if (state == ST_NOT_STARTED) {
        // 2. CAS 操作:确保只有一个线程能成功启动
        if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
            try {
                // 3. 真正的启动逻辑
                doStartThread();
            } catch (Throwable cause) {
                // 4. 启动失败,恢复状态
                STATE_UPDATER.set(this, ST_NOT_STARTED);
                PlatformDependent.throwException(cause);
            }
        }
    }
    // 5. 如果状态不是 ST_NOT_STARTED,直接返回(什么都不做)
}

三、关键点详解

1. 状态检查
if (state == ST_NOT_STARTED) {
    // 只有未启动状态才会进入
}

状态常量:

private static final int ST_NOT_STARTED = 1;     // 未启动
private static final int ST_STARTED = 2;         // 已启动
private static final int ST_SHUTTING_DOWN = 3;   // 正在关闭
private static final int ST_SHUTDOWN = 4;        // 已关闭
private static final int ST_TERMINATED = 5;      // 已终止

为什么要检查状态?

  • 避免重复启动线程
  • 如果已经启动过,直接返回
  • 性能优化:不需要进入 CAS 操作
2. CAS 操作(关键!)
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
    // 只有一个线程能成功执行到这里
}

STATE_UPDATER 是什么?

private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER =
    AtomicIntegerFieldUpdater.newUpdater(SingleThreadEventExecutor.class, "state");

CAS 的作用:

  • Compare And Set:比较并设置
  • 原子操作,线程安全
  • 只有一个线程能成功将状态从 ST_NOT_STARTED 改为 ST_STARTED

为什么需要 CAS?

假设没有 CAS,可能出现:

线程 A                    线程 B
   |                         |
   |--state == ST_NOT_STARTED|
   |                         |--state == ST_NOT_STARTED
   |                         |
   |--doStartThread()        |
   |                         |--doStartThread()  ❌ 重复启动!

有了 CAS:

线程 A                    线程 B
   |                         |
   |--state == ST_NOT_STARTED|
   |                         |--state == ST_NOT_STARTED
   |                         |
   |--CAS 成功 ✓             |
   |                         |--CAS 失败 ✓(状态已变)
   |                         |
   |--doStartThread()        |--直接返回
3. 异常处理
try {
    doStartThread();
} catch (Throwable cause) {
    // 启动失败,恢复状态
    STATE_UPDATER.set(this, ST_NOT_STARTED);
    PlatformDependent.throwException(cause);
}

为什么要恢复状态?

  • 如果启动失败,允许下次重试
  • 保持状态的一致性

四、doStartThread() 方法(核心)

private void doStartThread() {
    // 断言:确保 thread 为 null
    assert thread == null;
    
    // executor 是 ThreadPerTaskExecutor,会创建新线程
    executor.execute(new Runnable() {
        @Override
        public void run() {
            // ===== 这里是新线程的执行体 =====
            
            // 1. 将当前线程设置为 EventLoop 的线程
            thread = Thread.currentThread();
            
            // 2. 处理中断标志
            if (interrupted) {
                thread.interrupt();
            }
            
            boolean success = false;
            updateLastExecutionTime();
            
            try {
                // 3. 执行 EventLoop 的 run() 方法(死循环)
                SingleThreadEventExecutor.this.run();
                success = true;
            } catch (Throwable t) {
                logger.warn("Unexpected exception from an event executor: ", t);
            } finally {
                // 4. 清理工作(后面详细说明)
                // ...
            }
        }
    });
}

五、executor.execute() 做了什么?

executor 是 ThreadPerTaskExecutor:

public final class ThreadPerTaskExecutor implements Executor {
    private final ThreadFactory threadFactory;
    
    public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }
    
    @Override
    public void execute(Runnable command) {
        // 每次创建一个新线程并启动
        threadFactory.newThread(command).start();
    }
}

关键点:

  1. 每次调用 execute() 都会创建一个新线程
  2. 立即调用 thread.start() 启动线程
  3. 新线程会执行传入的 Runnable

threadFactory 是什么?

// 在 NioEventLoopGroup 初始化时创建
ThreadFactory threadFactory = new DefaultThreadFactory("nioEventLoop");

// DefaultThreadFactory 的实现
public class DefaultThreadFactory implements ThreadFactory {
    private final String prefix;
    private final AtomicInteger nextId = new AtomicInteger();
    
    @Override
    public Thread newThread(Runnable r) {
        // 创建线程,名字类似:nioEventLoop-1-1
        Thread t = new Thread(r, prefix + "-" + nextId.incrementAndGet());
        t.setDaemon(false);  // 非守护线程
        t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

六、新线程的执行流程

executor.execute(new Runnable() {
    @Override
    public void run() {
        // ===== 步骤 1:保存线程引用 =====
        thread = Thread.currentThread();
        
        // ===== 步骤 2:处理中断 =====
        if (interrupted) {
            thread.interrupt();
        }
        
        boolean success = false;
        updateLastExecutionTime();
        
        try {
            // ===== 步骤 3:执行 run() 方法(死循环)=====
            SingleThreadEventExecutor.this.run();
            success = true;
        } catch (Throwable t) {
            logger.warn("Unexpected exception from an event executor: ", t);
        } finally {
            // ===== 步骤 4:清理工作 =====
            // 4.1 更新状态为 SHUTTING_DOWN
            for (;;) {
                int oldState = state;
                if (oldState >= ST_SHUTTING_DOWN || 
                    STATE_UPDATER.compareAndSet(this, oldState, ST_SHUTTING_DOWN)) {
                    break;
                }
            }
            
            // 4.2 检查是否正确调用了 confirmShutdown()
            if (success && gracefulShutdownStartTime == 0) {
                logger.error("Buggy implementation; confirmShutdown() must be called");
            }
            
            try {
                // 4.3 执行剩余任务和关闭钩子
                for (;;) {
                    if (confirmShutdown()) {
                        break;
                    }
                }
            } finally {
                try {
                    // 4.4 清理资源
                    cleanup();
                } finally {
                    // 4.5 移除 FastThreadLocal
                    FastThreadLocal.removeAll();
                    
                    // 4.6 更新状态为 TERMINATED
                    STATE_UPDATER.set(this, ST_TERMINATED);
                    
                    // 4.7 释放信号量
                    threadLock.release();
                    
                    // 4.8 检查任务队列
                    if (!taskQueue.isEmpty()) {
                        logger.warn("terminated with non-empty task queue");
                    }
                    
                    // 4.9 设置终止 Future 为成功
                    terminationFuture.setSuccess(null);
                }
            }
        }
    }
});

七、NioEventLoop 的 run() 方法

@Override
protected void run() {
    // 死循环,直到 EventLoop 关闭
    for (;;) {
        try {
            // 1. select 操作(可能阻塞)
            switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
                case SelectStrategy.CONTINUE:
                    continue;
                case SelectStrategy.SELECT:
                    select(wakenUp.getAndSet(false));
                    if (wakenUp.get()) {
                        selector.wakeup();
                    }
                default:
            }
            
            cancelledKeys = 0;
            needsToSelectAgain = false;
            final int ioRatio = this.ioRatio;
            
            if (ioRatio == 100) {
                try {
                    // 2. 处理 IO 事件
                    processSelectedKeys();
                } finally {
                    // 3. 处理任务队列
                    runAllTasks();
                }
            } else {
                final long ioStartTime = System.nanoTime();
                try {
                    // 2. 处理 IO 事件
                    processSelectedKeys();
                } finally {
                    // 3. 根据 ioRatio 限制任务执行时间
                    final long ioTime = System.nanoTime() - ioStartTime;
                    runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
                }
            }
        } catch (Throwable t) {
            handleLoopException(t);
        }
        
        // 4. 检查是否需要关闭
        try {
            if (isShuttingDown()) {
                closeAll();
                if (confirmShutdown()) {
                    return;  // 退出循环
                }
            }
        } catch (Throwable t) {
            handleLoopException(t);
        }
    }
}

八、完整流程图

main 线程
   |
   |--eventLoop.execute(register0)
   |
   |--startThread()
   |    |
   |    |--state == ST_NOT_STARTED? ✓
   |    |
   |    |--CAS(ST_NOT_STARTED -> ST_STARTED) ✓
   |    |
   |    |--doStartThread()
   |         |
   |         |--executor.execute(new Runnable)
   |              |
   |              |--threadFactory.newThread(runnable)
   |              |
   |              |--thread.start()
   |              |
   |              +--> 新线程(nioEventLoop-1-1)
   |                      |
   |                      |--thread = Thread.currentThread()
   |                      |   (保存线程引用)
   |                      |
   |                      |--run() 死循环开始
   |                      |
   |                      |--for (;;) {
   |                      |     // 1. select IO 事件
   |                      |     select();
   |                      |     
   |                      |     // 2. 处理 IO 事件
   |                      |     processSelectedKeys();
   |                      |     
   |                      |     // 3. 处理任务队列
   |                      |     runAllTasks();
   |                      |       |
   |                      |       |--pollTask()
   |                      |       |   从 taskQueue 取出 register0
   |                      |       |
   |                      |       |--safeExecute(register0)
   |                      |       |   执行 register0 任务
   |                      |  }
   |                      |
   |                      |--循环继续...
   |
   |--返回(不等待线程执行完成)

九、关键设计点

1. 懒加载
// 构造方法中不创建线程
public NioEventLoop(...) {
    // 只初始化属性
    this.thread = null;  // 线程为 null
}

// 第一次调用 execute() 时才创建
eventLoop.execute(task);  // 触发 startThread()

好处:

  • 节省资源:不用的 EventLoop 不会创建线程
  • 延迟初始化:只在需要时创建
2. 单次启动保证
// 通过状态 + CAS 保证只启动一次
if (state == ST_NOT_STARTED) {  // 第一道防线
    if (CAS(ST_NOT_STARTED, ST_STARTED)) {  // 第二道防线
        doStartThread();
    }
}

即使多个线程同时调用 execute(),也只会启动一个线程。

3. 线程引用保存
// 在新线程中保存自己的引用
thread = Thread.currentThread();

作用:

  • 后续 inEventLoop() 方法需要用到
  • 判断当前线程是否是 EventLoop 线程

十、实际应用示例

示例 1:首次提交任务
// main 线程
EventLoopGroup group = new NioEventLoopGroup(1);
NioEventLoop eventLoop = (NioEventLoop) group.next();

// 此时 eventLoop.thread == null

// 第一次提交任务
eventLoop.execute(() -> {
    System.out.println("第一个任务");
});

// 执行流程:
// 1. startThread() 被调用
// 2. 创建新线程 "nioEventLoop-1-1"
// 3. 新线程开始执行 run() 方法
// 4. 从 taskQueue 取出任务并执行
示例 2:第二次提交任务
// 第二次提交任务
eventLoop.execute(() -> {
    System.out.println("第二个任务");
});

// 执行流程:
// 1. startThread() 被调用
// 2. state != ST_NOT_STARTED,直接返回
// 3. 任务加入队列
// 4. EventLoop 线程从队列取出并执行

十一、总结

startThread() 的核心逻辑
  1. 检查状态:只有未启动状态才会启动
  2. CAS 保证:确保只有一个线程能成功启动
  3. 创建线程:通过 ThreadPerTaskExecutor 创建新线程
  4. 保存引用:将新线程保存到 thread 变量
  5. 执行循环:新线程进入 run() 方法的死循环
关键设计
  • 懒加载:第一次提交任务时才创建线程
  • 单次保证:通过状态 + CAS 保证只启动一次
  • 线程安全:使用 AtomicIntegerFieldUpdater 保证并发安全
  • 异常处理:启动失败会恢复状态,允许重试
为什么这样设计?
  • 性能优化:不用的 EventLoop 不创建线程
  • 资源节省:避免创建不必要的线程
  • 线程安全:通过 CAS 避免重复启动
  • 简洁高效:一次启动,终身使用
【Netty源码分析】 客户端接入流程 服务端启动完成,这时候客户端连接就可以接入进来了,下面我们就来分析下客户端连接接入的流程。之前分析过线程启动方法是,由于这个方法里面的逻辑比较复杂,并没有展开,这一节就是从这个方法开始分析。 这个方法主要主要完成2件事:利用将的状态由修改成,即表示线程启动;执行方法;方法看着比较复杂,核心逻辑如下,向线程池执行器提交一个任务,而这个线程池执行器类型是,即每次执行任务都会创建一个新线程,而且这个任务是无限循环的:事件轮询、事件处理和任务队列处理,这样就和具体的线程进行了关联: 该方法大致完成2件事:: 阅读详情

相关推荐

SpringBoot+Vue+MySQL 高校学科竞赛平台 完整可运行版(源码+文档)

本项目基于SpringBoot+Vue+MySQL构建高校学科竞赛管理平台,覆盖学生、教师、领队教师、管理员四大角色,实现竞赛发布、报名、刷题、评分、公示等全流程闭环管理。系统架构清晰,技术主流,配套完整源码、数据库脚本、万字论文、开题报告、答辩PPT及部署文档,支持一键运行,适用于毕业设计、课程设计及院系二次开发,真正实现“开箱即用”。

招风的黑耳优快云 183

Netty核心源码分析(五)核心组件EventLoop源码分析

当第一次添加时就启动线程,执行 run 方法,而 run 方法是整个 EventLoop 的核心,就像 EventLoop 的名字一样,Loop Loop ,不停的 Loop ,Loop 做什么呢?大致的逻辑就是:调用NIO的selector的select方法,默认阻塞一秒钟,如果有定时任务,则在定时任务剩余时间的基础上再加上0.5秒进行阻塞。(4)EventLoop是一个单例的线程池,里面含有一个死循环的线程不断地做着三件事情:监听端口、处理端口事件、处理队列事件。(1)select获取感兴趣的事件。

秃了也弱了 976

NLM去噪算法:原理、优化与医学图像处理实战

本文深入解析NLM去噪算法的核心原理及其在医学图像处理中的优化应用。通过全局自相似性计算,NLM算法有效抑制噪声并保留细节,特别适用于超声图像斑点噪声处理。文章还介绍了积分图像和傅里叶变换等优化技巧,显著提升计算效率,并分享医学影像项目中的实用调参经验。

weixin_29051149的博客 348

netty4源码分析——NioEventLoop

有关NioEventLoop的继承结构如下图: NioEventLoop是Netty的Reactor线程,它的职责如下: 1.    作为服务端Acceptor线程,负责处理客户端的请求接入; 2.    作为客户端Connecor线程,负责注册监听连接操作位,用于判断异步连接结果; 3.    作为IO线程,监听网络读操作位,负责从SocketChannel中读取报文; 4.

风居住的城市 835

【python快速编程入门(第二版)黑马程序员课后编程题】

python快速编程入门(第二版)黑马程序员课后编程题

weixin_46167259的博客 1万+

数字孪生成熟度的L0-L4五级划分,各自特征和应用场景

数字孪生的分级(或成熟度模型)通常用于描述其技术复杂度和功能完备性的演进过程。3D设计模型(CAD)、建筑信息模型(BIM)、产品数字化手册。全自动驾驶系统、自适应智能电网、 “黑灯工厂”的自主调度。多学科模型融合、 “What-if”分析、提供决策建议。IoT设备监控平台、预测性维护(报警)、智慧仪表盘。工艺仿真优化、资产性能管理、手术方案预演、虚拟调试。状态监控、历史回溯、阈值报警、根因分析。可视化、数字化档案。自优化、自适应、目标驱动、高度自治。传统设备、纸质记录的管理模式。无或仅有离线、孤立数据。

2401_82881178的博客 1555

Netty源码分析---execute-method解析

Netty的SingleThreadEventExecutor.execute()方法核心流程:首先校验任务非空,判断当前线程是否为EventLoop线程;然后将任务加入队列。若非EventLoop线程提交任务,会启动EventLoop线程(仅首次调用时真正启动),并处理可能的关闭状态异常。该方法通过CAS确保线程安全启动,最终EventLoop线程会进入处理IO事件和执行队列任务的死循环。整个过程实现了线程安全的任务提交与执行机制。

java_rutu的博客 685

ECC密码的加密和解密(附带代码实现)

ECC,全称Elliptic Curve Cryptography,是椭圆曲线密码学。这是一种公钥加密技术,其安全性基于椭圆曲线离散对数问题,被广泛应用于信息安全领域。ECC的主要优势在于,相较于RSA和DSA等其他传统的公钥密码体系,它能够在提供相同安全级别的情况下,使用更短的密钥,从而减少计算量和存储空间的需求。例如,一个256位的ECC密钥提供的安全性可以与3072位的RSA密钥或DSA密钥相媲美。ECC的主要应用领域包括SSL安全证书、安全电子邮件、移动设备安全、物联网设备安全等。

xixixi7777的博客 8273

Netty源码分析--Channel注册(中)(六)

接上一篇,我们继续看 不知道大家第一次看这段代码的时候有没有一脸懵逼,反正我是一脸懵,为什么这个if else 最终都是调用的register0方法,都是一样的。 其实这里就是为什么Netty是线程安全的根本原因。 我们先看下eventLoop.inEventLoop() 方法 第一张图传入了 当前的 线程, 第二...

weixin_30952103的博客 138

WPF实现圆形菜单动态展开折叠效果

实现效果如下: 思路:根据子菜单个数计算旋转角度动态生成子菜单,并设置展开折叠动画。 步骤: 1、自定义按钮MyButton,建立展示图像属性DisplayImage public class MyButton : Button { public static readonly DependencyProperty DisplayImageProperty = DependencyProperty.Register("DisplayImage", typeof(

dnazhd的博客 3151

MATLAB算法实战应用案例精讲-【数模应用】装箱问题

装箱问题可以根据不同的维度进行分类。以下是一些常见的装箱问题二维装箱问题:二维装箱问题假设所有物品都是平面上的矩形,并且需要将它们放入平面上的容器中。这个问题的目标是找到一种装箱方案,使得物品不重叠并占据的总面积最小。三维装箱问题:三维装箱问题考虑到物品可以具有高度,并且需要将它们放入三维容器(如箱子或货柜)中。目标是找到一种装箱方案,使得物品不重叠且总体积最小。多维装箱问题:多维装箱问题是指在更高维度空间中进行装箱的问题。除了长度和宽度之外,物品可能具有其他属性,如高度、重量、形状等。

qq_36130719的博客 1572

【Netty系列_5】揭开NioEventLoop的面纱

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情 说明: 1. 本文以问题引言和debug的方式,探究NioEventLoop的底层逻辑 2. 由于历史原因,本文使用的代码为编译后的(仅部分为没编译的源代码) 3. 本文为了看起来目录清晰些,目录结构以调用链为基准以树形结构排版 问题: 在开篇前,我们先抛出几个问题,让我们带着问题去阅读本文,不至于读完...

my的博客 238

基于Simulink环境,提供一个关于如何对无人机电源DC-DC变换器进行仿真建模的示例

无人机电源要求:无人机的各个子系统(如电机、传感器、通信模块等)可能需要不同级别的电压供应。重要性稳定性:稳定的电源是保证无人机各部件正常工作的基础。效率:高效的电源管理可以显著增加飞行时间和任务执行能力。挑战多负载适应性:需要能够为不同负载提供合适的电压和电流。动态响应:快速响应负载变化的能力对于维持系统稳定性至关重要。首先明确要模拟的任务内容。设计一个能够在不同负载条件下为无人机提供稳定电压的DC-DC变换器。根据无人机的工作状态调整控制策略以维持最佳性能。

xiaoheshang_123的博客 136

InnoDB 内存结构总览:Change Buffer、AHI 与 Log Buffer

本文系统梳理InnoDB内存结构中的ChangeBuffer、Adaptive Hash Index(AHI)与LogBuffer。ChangeBuffer缓存二级索引页不在内存时的变更,减少随机IO,仅在页加载时合并;聚簇索引修改立即执行,因数据本身不可延后。AHI基于高频等值查询自动构建哈希索引,加速定位,仅支持等值操作。LogBuffer为redo log内存缓冲,配合磁盘日志实现崩溃恢复。三者均服务于性能优化,其中ChangeBuffer与AHI共享BufferPool空间,而LogBuffer独立

bksczm的博客 298

【Unity实战篇 】| Unity实现 文本框可以自适应大小,到达最大宽度之后再缩小字体

Unity实现 Text文本框可以自适应大小,到达最大宽度之后再缩小字体 需求:在文本框可以自适应大小拉伸的前提下,增加一个最大限制宽度,使其到达最大宽度后 再启用 Best Fit 实现自适应改变文字大小以适应文本框的大小。 在Unity中经常会用到文本组件的自适应大小功能,一般使用HorizontalLayoutGroup和ContentSizeFitter组件配合即可实现文本自适应的效果。

努力前行,总会成为自己心中的那道光 3万+

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

信创环境下PageOffice文档控件适配与实践

信创适配做到文档控件这一层,拼的已经不是"有没有国产版本",而是同一个功能在两类终端上是否真的等价。等价的标准很具体:同一次点击能得到同样的结果,同一份公文能得到同样的版式,同一个项目不需要维护两套代码。这背后是三件并不轻松的工作:服务端用一套接口同时支撑两类终端,客户端把两种系统与四种芯片的安装包分发清楚,文档内核层由产品侧跟着 WPS 的版本走。浏览器这一层的压力,则被收进了产品自己的窗口里——升级节奏由产品掌握,不再交给运气。

zi_wu_xian的专栏 327

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

第三篇 第 6 课

前置:第三篇第 1 课(stdx 引入),第二篇第 1 课(std.regex)。环境:仓颉 SDK 1.2.0。本文所有代码与输出均逐行实测。

weixin_41618057的博客 516

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

V8 机制、手写核心函数与 TypeScript 类型体操

或固定初始化(如数组先定长、对象先给全字段)保持类型与形状稳定;这些都比"换框架"更基础。只能处理纯数据(丢函数、Date、RegExp、循环引用报错)。生产级深拷贝要处理:原始值短路、循环引用、V8(Chrome / Node 的 JS 引擎)不是"解释一行跑一行"那么简单,它用。图:V8 执行流程——解释执行 + 热点优化,优化失败会 Deopt 回退。JS 内存自动管理,但"自动"不等于"不会漏"。是"固定间隔最多执行一次"。手写 Promise 是"懂异步"的试金石。是"停下后才执行最后一次",

qq_38468358的博客 351

【从零理解 Spring AI · 12】MCP 的两种角色:做客户端还是做服务端

上一篇讲了 MCP 的概念:标准协议、三大角色、M+N 替代 M×N。

nice_lcj520的博客 538

Java 集合容器高频面试题全解:HashMap 树化阈值、1.7 死循环与 ConcurrentHashMap 演进(2026 招聘 JD 真题复盘)

HashMap 树化阈值 8 的泊松分布依据、退化阈值 6 的防抖设计、JDK 1.7 头插成环死循环的排查与修复、1.8 尾插后为何仍线程不安全、ConcurrentHashMap 放弃分段锁的原因与 ForwardingNode 协作扩容、computeIfAbsent 死锁陷阱、大集合找重复的场景题选型,附三层追问链自测。题目来源为 38 期公开招聘 JD 样本与字节、拼多多、建行、美团、快手公开面经。

蒙眼过河 420

spdlog 同步日志库使用详解

spdlog是一个轻量级 C++ 日志库,支持同步日志、异步日志、多线程日志、日志文件轮转和自定义日志格式。对于嵌入式 Linux 应用开发,我建议先使用。它可以帮我们完成:日志级别过滤。时间戳和线程 ID 输出。日志格式化。终端和文件输出。多线程安全写入。日志文件按大小或时间轮转。我们不需要自己实现互斥锁、文件写入、日志格式化和轮转等底层功能。

zengjiajun2006的博客 1120

JavaSE通关手册:数据类型与变量

代码无需额外处理,编译时编译器自动完成转换。

xys_678的博客 221

Java 多态 学习笔记

多态是面向对象编程的重要特性,指同一操作作用于不同对象时产生不同行为。其核心在于“父类引用指向子类对象”,结合方法重写实现运行时动态绑定。多态使代码更灵活、可扩展,如用Person p = new Student();统一处理各类人员注册,无需修改调用逻辑。但多态无法直接调用子类特有方法,需通过instanceof判断并强制转换。编译时看左边(类型),运行时看右边(实际对象),实现解耦与维护便利。

AA_AA114514的博客 367

IDEA 简介:从零认识 IntelliJ IDEA

IDEA 全称,是由 JetBrains 公司开发的一款主流 Java 集成开发环境(IDE)。它集代码编辑、编译、调试、测试、版本控制、构建管理等功能于一体,被大量 Java 开发者视为日常开发的首选工具。所谓 IDE(Integrated Development Environment,集成开发环境),就是把写代码所需的各类工具整合到同一个界面中。相比只用文本编辑器加命令行编译,IDE 能显著减少重复操作,让开发者把精力集中在业务逻辑上。

ztI10的博客 174

Java实现批量线段相交检测(跨积判定+扫描线优化与踩坑复盘)

【代码】Java实现批量线段相交检测(跨积判定+扫描线优化与踩坑复盘)

m0_64476639的博客 341

c++ explicit关键字详解

explicit。

拒绝AI文,努力在AI时代写出感动人心的好文章 152
上一篇: Netty源码分析---SingleThreadEventLoop与EventLoop关系详解
下一篇: Netty源码分析---编码器深度解析-简约版
不早睡不改名@
博客等级 码龄5年 536粉丝 306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值