Netty笔记10-Netty参数调优

文章目录

  • 一、CONNECT_TIMEOUT_MILLIS
    • CONNECT_TIMEOUT_MILLIS设置为1秒超时
    • CONNECT_TIMEOUT_MILLIS设置为5秒超时
    • 注意事项
  • 二、SO_BACKLOG
    • 代码示例
    • 注意事项
  • 三、ulimit -n(文件描述符)
    • 设置文件描述符限制
    • 在注意事项
  • 四、TCP_NODELAY
    • 使用 TCP_NODELAY 的场景
    • 注意事项
  • 五、SO_SNDBUF & SO_RCVBUF
    • SO_SNDBUF(发送缓冲区)
      • 作用
    • SO_RCVBUF(接收缓冲区)
      • 作用
  • 六、ALLOCATOR
  • 七、RCVBUF_ALLOCATOR


一、CONNECT_TIMEOUT_MILLIS

在Netty中,CONNECT_TIMEOUT_MILLIS 是一个与连接超时相关的配置选项。这个选项用于设置客户端在尝试建立连接时的最大等待时间。如果在指定的时间内未能成功建立连接,Netty 将会抛出一个 ConnectTimeoutException 异常。

  • 属于 SocketChannal 参数
  • 用在客户端建立连接时,如果在指定毫秒内无法连接,会抛出 timeout 异常
  • SO_TIMEOUT 主要用在阻塞 IO,阻塞 IO 中 accept,read 等都是无限等待的,如果不希望永远阻塞,使用它调整超时时间
  1. 客户端通过 .option() 方法配置参数 给 SocketChannel 配置参数

  2. 服务器端
    new ServerBootstrap().option() ,是给 ServerSocketChannel 配置参数
    new ServerBootstrap().childOption() ,给 SocketChannel 配置参数

CONNECT_TIMEOUT_MILLIS设置为1秒超时

option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)

不启动服务器端直接启动客户端观察控制台

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Test02ConnectionTimeout {
    public static void main(String[] args) {
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap()
                    .group(group)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
                    .channel(NioSocketChannel.class)
                    .handler(new LoggingHandler());
            ChannelFuture future = bootstrap.connect("127.0.0.1", 8080);
            ChannelFuture channelFuture = future.sync();//当1秒内没有连接成功,则判断为连接超时所以抛出异常
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
            log.debug("timeout");
        } finally {
            group.shutdownGracefully();
        }
    }
}

控制台输出

io.netty.channel.ConnectTimeoutException: connection timed out: /127.0.0.1:8080

CONNECT_TIMEOUT_MILLIS设置为5秒超时

option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Test02ConnectionTimeout {
    public static void main(String[] args) {
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap()
                    .group(group)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                    .channel(NioSocketChannel.class)
                    .handler(new LoggingHandler());
            ChannelFuture future = bootstrap.connect("127.0.0.1", 8080);
            ChannelFuture channelFuture = future.sync();//当1秒内没有连接成功,则判断为连接超时所以抛出异常
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
            log.debug("timeout");
        } finally {
            group.shutdownGracefully();
        }
    }
}

控制台输出

io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8080
Caused by: java.net.ConnectException: Connection refused: no further information

观察发现ChannelOption.CONNECT_TIMEOUT_MILLIS超时时间设置1秒和5秒时报错信息不同,原因是:

  • 设置为5秒是因为在没有启动服务器端时,客户端两秒后判断出服务器端没启动,所以根本连不上。所以直接报错。
  • 设置为1秒是因为还不能判断服务器端是否启动就已经超时了,所以报错连接超时。

注意事项

  • 合理设置超时时间:根据应用场景和网络状况合理设置超时时间。如果网络条件较差,可以适当增加超时时间;如果对响应时间有严格要求,则可以缩短超时时间。
  • 异常处理:在代码中处理 ConnectTimeoutException,可以记录日志,并根据业务需求决定是否重试连接等。
  • 重试机制:可以实现一个重试机制,在首次连接失败后尝试多次连接,直到成功或达到最大重试次数。
  • 监控和报警:设置监控来检测连接超时的发生,并在必要时触发报警,以便及时处理潜在的问题。

二、SO_BACKLOG

在Netty中,SO_BACKLOG 是一个与 TCP 服务器端套接字相关的选项,用于设置在服务器的连接请求队列中可以排队的最大连接数。当客户端尝试连接到服务器时,如果服务器正忙于处理其他连接请求,新的连接请求会被放入这个队列中等待处理。SO_BACKLOG 的值决定了这个队列的最大长度。

Netty中SO_BACKLOG属于 ServerSocketChannal 参数
在这里插入图片描述

  1. 第一次握手,client 发送 SYN 到 server,状态修改为 SYN_SEND,server 收到,状态改变为 SYN_REVD,并将该请求放入 sync queue 队列(半连接队列)
  2. 第二次握手,server 回复 SYN + ACK 给 client,client 收到,状态改变为 ESTABLISHED,并发送 ACK 给 server
  3. 第三次握手,server 收到 ACK,状态改变为 ESTABLISHED,将该请求从 sync queue 放入 accept queue(全连接队列)

其中

  • 在 linux 2.2 之前,backlog 大小包括了两个队列的大小,在 2.2 之后,分别用下面两个参数来控制
  • sync queue - 半连接队列
  • 大小通过 /proc/sys/net/ipv4/tcp_max_syn_backlog 指定,在
    syncookies 启用的情况下,逻辑上没有最大值限制,这个设置便被忽略
  • accept queue - 全连接队列
  • 其大小通过 /proc/sys/net/core/somaxconn 指定,在使用 listen 函数时,内核会根据传入的 backlog 参数与系统参数,取二者的较小值
  • 如果 accpet queue 队列满了,server 将发送一个拒绝连接的错误信息到 client

在netty中可以通过 option(ChannelOption.SO_BACKLOG, 值) 来设置大小

代码示例

public class TestBacklogServer {
    public static void main(String[] args) {
        new ServerBootstrap()
                .group(new NioEventLoopGroup())
                .option(ChannelOption.SO_BACKLOG, 2)
                // 验证全队列满了,客户端在进行连接会报错ConnectException: Connection refused: no further information
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) {
                        ch.pipeline().addLast(new LoggingHandler());
                    }
                }).bind(8080);
    }
}
@Slf4j
public class TestBacklogClient {
    public static void main(String[] args) {
        NioEventLoopGroup worker = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.group(worker);
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {

                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new LoggingHandler());
                    ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
                            ctx.writeAndFlush(ctx.alloc().buffer().writeBytes("hello!".getBytes()));
                        }
                    });
                }
            });
            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("client error", e);
        } finally {
            worker.shutdownGracefully();
        }
    }
}

第三个客户端连接时报错:

Connected to the target VM, address: '127.0.0.1:43839', transport: 'socket'
19:58:44 [DEBUG] [nioEventLoopGroup-2-1] i.n.h.l.LoggingHandler - [id: 0x95677ae0] REGISTERED
19:58:44 [DEBUG] [nioEventLoopGroup-2-1] i.n.h.l.LoggingHandler - [id: 0x95677ae0] CONNECT: /127.0.0.1:8080
19:58:46 [DEBUG] [nioEventLoopGroup-2-1] i.n.h.l.LoggingHandler - [id: 0x95677ae0] CLOSE
Exception in thread "main" io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information: /127.0.0.1:8080
Caused by: java.net.ConnectException: Connection refused: no further information

注意事项

  1. 操作系统限制:SO_BACKLOG 的实际效果受到操作系统的限制。在 Linux 上,SO_BACKLOG 的值通常会被限制在 somaxconn 系统参数范围内。可以通过查看当前linux系统的 somaxconn 值,并通过 sysctl 命令进行调整。
# 查看 somaxconn 的值
cat /proc/sys/net/core/somaxconn

# 设置 somaxconn 的值
sysctl net.core.somaxconn=1024
  1. 队列满后的处理:如果 SO_BACKLOG 队列满了,新的连接请求将会被拒绝。在这种情况下,客户端会收到一个连接失败的错误。因此,合理设置 SO_BACKLOG 的值很重要,以确保不会因为队列满而导致连接请求被拒绝。
  2. 性能影响:虽然设置较高的 SO_BACKLOG 值可以容纳更多的连接请求,但也可能占用更多的系统资源。因此,需要根据实际的并发需求和系统性能来权衡 SO_BACKLOG 的值。

三、ulimit -n(文件描述符)

文件描述符是操作系统分配给进程用于表示打开的文件、网络连接等资源的整数标识符。在 Linux 和 Unix-like 系统中,每个进程都有一个文件描述符的上限,这个上限由 ulimit -n 命令来查看和设置。
文件描述符是操作系统用来跟踪进程所打开的文件和其他 I/O 资源(如网络连接、管道等)的内部索引。每个打开的文件或 I/O 资源都有一个唯一的文件描述符与之关联。

  • ulimit -n 属于操作系统参数
    作用:显示一个线程同时打开最大文件描述符(FD)的数量,当FD到达上限在打开文件会报错。如果服务器要支持高并发,支持大量的连接就需要调整ulimit参数。

设置文件描述符限制

# 查看当前用户的软限制
ulimit -n

# 设置新的软限制
ulimit -n 65536

# 查看新的软限制
ulimit -n

在注意事项

  • 安全性:增加文件描述符限制可能会增加系统资源的消耗,因此需要根据实际需求和系统能力来设置合适的限制值。
  • 性能:增加文件描述符限制可能会导致系统开销增加,特别是在高并发场景下,因此需要权衡利弊。
  • 系统限制:有些系统对文件描述符的总数有严格的限制,即使你是 root 用户也无法无限制地增加文件描述符的数量。

四、TCP_NODELAY

在Netty中,TCP_NODELAY 是一个与TCP协议相关的选项,用于控制是否禁用Nagle算法。Nagle算法是为了减少小数据包在网络中的传输次数,以减少网络带宽的消耗和网络拥塞。然而,在某些需要低延迟的应用场景中,禁用Nagle算法可以提高实时性能。

  • TCP_NODELAY 属于 SocketChannal 参数
  • 默认false开启了nagle算法(沾包问题数据攒到一起发送),但是一般都需要消息可以及时的发送出去。所以设置为true
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

public class Client {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                     .channel(NioSocketChannel.class)
                     .option(ChannelOption.TCP_NODELAY, true) // 设置 TCP_NODELAY 为 true
                     .handler(new MyClientInitializer());

            // 连接到服务器
            ChannelFuture future = bootstrap.connect("127.0.0.1", 8080).sync();
            if (!future.isSuccess()) {
                System.err.println("Failed to connect: " + future.cause());
            }
        } finally {
            group.shutdownGracefully();
        }
    }
}
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class Server {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 主线程组,用于接受新的连接
        EventLoopGroup workerGroup = new NioEventLoopGroup(); // 工作线程组,用于处理连接上的数据

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                     .channel(NioServerSocketChannel.class)
                     .option(ChannelOption.SO_BACKLOG, 128)
                     .childOption(ChannelOption.TCP_NODELAY, true) // 设置 TCP_NODELAY 为 true
                     .childHandler(new ChannelInitializer<NioSocketChannel>() {
                         @Override
                         protected void initChannel(NioSocketChannel ch) {
                             ch.pipeline().addLast(new LoggingHandler());
                         }
                     });

            // 绑定端口并开始监听
            ChannelFuture future = bootstrap.bind(8080).sync();
            future.channel().closeFuture().sync(); // 等待服务器 socket 关闭
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

使用 TCP_NODELAY 的场景

  1. 实时应用
    在实时应用(如在线游戏、实时视频会议等)中,通常需要尽可能低的延迟。在这种情况下,禁用Nagle算法可以提高实时性能,因为数据包会立即发送,而不会被累积。
  2. 高吞吐量应用
    在需要高吞吐量的应用中,累积数据包可以减少网络带宽的消耗。因此,在这类应用中,可以保留Nagle算法的默认设置。

注意事项

性能影响:禁用Nagle算法会增加网络带宽的消耗,尤其是在发送小数据包的情况下。因此,在设置 TCP_NODELAY 之前,需要评估其对性能的影响。
兼容性:确保客户端和服务器端都设置了相同的 TCP_NODELAY 值,以避免由于配置不一致而导致的问题。

五、SO_SNDBUF & SO_RCVBUF

在Netty中,SO_SNDBUF 和 SO_RCVBUF 是两个与套接字缓冲区相关的选项,它们分别用于控制发送缓冲区和接收缓冲区的大小。这两个选项可以帮助优化网络通信性能,特别是在高并发或大数据量传输的场景下。

  • SO_SNDBUF 属于 SocketChannal 参数
  • SO_RCVBUF 既可用于 SocketChannal 参数,也可以用于 ServerSocketChannal 参数(建议设置到 ServerSocketChannal 上)
    这两个参数决定了滑动窗口的上限。一般不建议手动添加,因为操作系统一般会根据通信双方的网络通信能力来调整这两个参数。

SO_SNDBUF(发送缓冲区)

SO_SNDBUF 选项用于设置发送缓冲区的大小。发送缓冲区是操作系统用来暂时存储待发送的数据的一个区域。当应用程序向网络发送数据时,数据首先被写入发送缓冲区,然后由操作系统负责将数据发送到网络上。

作用

提高发送速度:较大的发送缓冲区可以让应用程序更快地将数据写入缓冲区,而不必等待数据实际发送完毕。
减少阻塞:如果发送缓冲区太小,当网络拥塞或接收方处理较慢时,应用程序可能会因为缓冲区满而被阻塞。

SO_RCVBUF(接收缓冲区)

SO_RCVBUF 选项用于设置接收缓冲区的大小。接收缓冲区是操作系统用来暂时存储从网络接收的数据的一个区域。当数据从网络到达时,首先被写入接收缓冲区,然后由应用程序负责从缓冲区中读取数据。

作用

提高接收速度:较大的接收缓冲区可以让操作系统更快地接收数据,而不必等待应用程序处理完毕。
减少丢包:如果接收缓冲区太小,当网络流量较大或应用程序处理较慢时,可能会导致数据包丢失。

六、ALLOCATOR

  • 属于 SocketChannal 参数
  • 用来分配 ByteBuf, ctx.alloc()
    ByteBuf默认使用PooledUnsafeDirectByteBuf
@Slf4j
public class Test04ByteBuf {
    public static void main(String[] args) {
        new ServerBootstrap()
                .group(new NioEventLoopGroup())
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) {
                        ch.pipeline().addLast(new LoggingHandler());
                        ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                ByteBuf buf = ctx.alloc().buffer();
                                log.debug("alloc buf {}", buf);
                                //alloc buf PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 256)

                                //在设置中VM options配置-Dio.netty.allocator.type=unpooled
                                //alloc buf UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf(ridx: 0, widx: 0, cap: 256)

                                //在设置中VM options配置-Dio.netty.allocator.type=unpooled -Dio.netty.noPreferDirect=true
                                //alloc buf UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 256)
                                
//                                log.debug("receive buf {}", msg);
//                                System.out.println("");
                            }
                        });
                    }
                }).bind(8080);
    }
}

在这里插入图片描述

七、RCVBUF_ALLOCATOR

在Netty中,RCVBUF_ALLOCATOR 是一个与接收缓冲区大小相关的配置选项,它用于控制接收缓冲区的初始大小和最大大小。这个配置选项可以帮助优化网络通信性能,特别是在高并发或大数据量传输的场景下。
RCVBUF_ALLOCATOR 用于控制接收缓冲区的分配策略。接收缓冲区是操作系统用来暂时存储从网络接收的数据的一个区域。当数据从网络到达时,首先被写入接收缓冲区,然后由应用程序负责从缓冲区中读取数据。

  • 属于 SocketChannal 参数
  • 控制 netty 接收缓冲区大小
  • 负责入站数据的分配,决定入站缓冲区的大小(并可动态调整),统一采用 direct 直接内存,具体池化还是非池化由 allocator 决定

全部文章:
Netty笔记01-Netty的基本概念与用法
Netty笔记02-组件EventLoop
Netty笔记03-组件Channel
Netty笔记04-组件Future & Promise
Netty笔记05-组件Handler & Pipeline
Netty笔记06-组件ByteBuf
Netty笔记07-粘包与半包(上)
Netty笔记08-粘包与半包(下)
Netty笔记09-网络协议设计与解析
Netty笔记10-Netty参数调优

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JavaWeb--纯小白笔记03:servlet入门---动态网页的创建

笔记&#xff1a;index.html在tomcat中为默认的名字&#xff0c;html里面的语法不严谨。改配置文件要小心&#xff0c;不然容易删掉其他 Servlet&#xff1a;服务器端小程序&#xff0c;写动态网页需要用Servlet&#xff0c;普通的java类通过继承HttpServlet&#xff0c;可以响…

【重学 MySQL】三十一、字符串函数

【重学 MySQL】三十一、字符串函数 函数名称用法描述ASCII(S)返回字符串S中的第一个字符的ASCII码值CHAR_LENGTH(s)返回字符串s的字符数&#xff0c;与CHARACTER_LENGTH(s)相同LENGTH(s)返回字符串s的字节数&#xff0c;和字符集有关CONCAT(s1,s2,…,sn)连接s1,s2,…,sn为一个字…

Docker + Win 10 学习记录

下载Docker Release notes | Docker Docs 推荐使用4.33版本&#xff0c;最新的Docker版本在win10 22H2无法安装。需要升级到win11. 查看Win10版本是否与最新版的Docker兼容 运行 win R&#xff0c; 然后输入winver 如果你的Docker版本无法在当前的win10安装&#xff0c;请更…

828华为云征文|华为云Flexus云服务器X实例部署Xnote笔记应用

828华为云征文&#xff5c;华为云Flexus云服务器X实例部署Xnote笔记应用 前言一、Flexus云服务器X实例介绍1.1 Flexus云服务器X实例简介1.2 Flexus云服务器X实例特点1.3 Flexus云服务器X实例使用场景 二、Note Mark 介绍2.1 Xnote简介2.2 Xnote特点2.3 主要使用场景 三、本次实…

豆包Python SDK接入流程

模型与价格 豆包的模型介绍可以看豆包大模型介绍&#xff0c;模型价格可以看豆包定价文档里的“模型推理” - “大语言模型” - “字节跳动”部分。 推荐使用以下模型&#xff1a; Doubao-lite-32k&#xff1a;每百万 token 的输入价格为 0.3 元&#xff0c;输出价格为 0.6 元…

JavaEE: 深入探索TCP网络编程的奇妙世界(六)

文章目录 TCP核心机制TCP核心机制九: 面向字节流TCP核心机制十: 异常处理 小小的补充(URG 和 PSH)~TCP小结TCP/UDP 对比用UDP实现可靠传输(经典面试题) 结尾 TCP核心机制 上一篇文章JavaEE: 深入探索TCP网络编程的奇妙世界(五) 书接上文~ TCP核心机制九: 面向字节流 TCP是面…

桶排序和计数排序(非比较排序算法)

桶排序 桶排序是一种基于分配的排序算法&#xff0c;特别适合用来排序均匀分布的数据。它的基本思想是将输入的数据分到有限数量的桶里&#xff0c;然后对每个桶内的数据分别进行排序&#xff0c;最后再将各个桶内的数据合并得到最终的排序结果。(通常用于浮点数&#xff0c;因…

Linux:RPM软件包管理以及yum软件包仓库

挂载光驱设备 RPM软件包管理 RPM软件包简介 区分软件名和软件包名 软件名&#xff1a;firefox 软件包名&#xff1a;firefox-52.7.0-1.el7.centos.x86_64.rpm 查询软件信息 查询软件&#xff08;参数为软件名&#xff09; ]# rpm -qa #当前系统中所有已安装的软件包 ]# r…

WebGL颜色与纹理

WEBGL中的着色器变量包括以下种类&#xff1a; 属性变量&#xff08;Attribute Variables&#xff09;&#xff1a;这些变量用于接收从应用程序中传递的顶点数据&#xff0c;比如顶点位置和颜色&#xff0c;是只读的不可修改。统一变量&#xff08;Uniform Variables&#xff…

AI浪潮新崛起:借助AI+实景/视频直播创新魅力,开启无人自动直播新时代!

AI浪潮新崛起&#xff1a;借助AI实景/视频直播创新魅力&#xff0c;开启无人自动直播新时代&#xff01; 在科技日新月异的今天&#xff0c;人工智能&#xff08;AI&#xff09;已不再仅仅是科幻电影中的桥段&#xff0c;它正以不可阻挡之势渗透到我们生活的方方面面&#xff…

力扣718-最长重复子数组(Java详细题解)

题目链接&#xff1a;718. 最长重复子数组 - 力扣&#xff08;LeetCode&#xff09; 前情提要&#xff1a; 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 dp五部曲。 1.确定dp数组和i下标的含义。 2.确定递推公式。 3.dp初始化。 4.确定dp的遍历顺序。 5…

【编程底层原理】Java常用读写锁的使用和原理

一、引言 在Java的并发世界中&#xff0c;合理地管理对共享资源的访问是至关重要的。读写锁&#xff08;ReadWriteLock&#xff09;正是一种能让多个线程同时读取共享资源&#xff0c;而写入资源时需要独占访问的同步工具。本文将带你了解读写锁的使用方法、原理以及它如何提高…

这8款AI论文工具帮你一键搞定!ai论文一键生成任务书

在当今学术研究和论文写作领域&#xff0c;AI技术的应用已经成为一种趋势。通过智能算法和大数据分析&#xff0c;AI工具能够帮助学者和学生提高写作效率、优化内容结构&#xff0c;并确保论文的原创性和质量。以下是8款值得推荐的AI论文工具&#xff0c;其中特别推荐千笔-AIPa…

选择排序(C语言实现)

目录 1.基本思想 2.代码实现 代码思路 代码实现 代码测试 3.复杂度分析 1&#xff09;时间复杂度 2&#xff09;空间复杂度 4.特性总结 1.基本思想 选择排序是一种简单直观的比较排序算法。该算法的基本思想是在每一轮中选出当前未排序部分的最小&#xff08;或最大&a…

通过 LabVIEW 正则表达式读取数值(整数或小数)

在LabVIEW开发中&#xff0c;字符串处理是一个非常常见的需求&#xff0c;尤其是在处理包含复杂格式的数字时。本文通过一个具体的例子来说明如何利用 Match Regular Expression Function 和 Match Pattern Function 读取并解析字符串中的数字&#xff0c;并重点探讨这两个函数…

日期和时间类【Date】【Calendar日历类】【LocalDate】Date-Time API详解

我们先来介绍一下与时间相关的基础知识。 GMT - 格林尼治标准时间&#xff08;Greenwich Mean Time&#xff09;&#xff0c;简称GMT&#xff0c;实际上与世界时UT&#xff08;universal time &#xff09;基本一致。 UTC - 协调世界时&#xff08;Universal Time Coordinated&…

matlab恢复默认窗口布局

1.点击主页&#xff0c;选择布局 2.选择默认&#xff0c;即可恢复到默认的窗口布局

Linux系统上搭建Vulhub靶场

Linux系统上搭建Vulhub靶场 ​vulhub​ 是一个开源的漏洞靶场&#xff0c;它提供了各种易受攻击的服务和应用程序&#xff0c;供安全研究人员和学习者测试和练习。要在 Linux 系统上安装和运行 vulhub​&#xff0c;可以按照以下步骤进行&#xff1a; 1. 安装 Docker 和 Docke…

C#软键盘设计字母数字按键处理相关事件函数

应用场景&#xff1a;便携式设备和检测设备等小型设备经常使用触摸屏来代替键盘鼠标的使用&#xff0c;因此在查询和输入界面的文本或者数字输入控件中使用软件盘来代替真正键盘的输入。 软键盘界面&#xff1a;软键盘界面实质上就是一个普通的窗体上面摆放了很多图片按钮&…

二叉树---java---黑马

二叉树 遍历 遍历分两种 广度优先遍历 尽可能先访问距离根节点最近的节点&#xff0c;也称之为层序遍历。 深度优先遍历 对于二叉树&#xff0c;进一步分为三种 pre-order前序遍历&#xff0c;对于每一颗子树&#xff0c;先访问该节点&#xff0c;然后是左子树&#xf…