Netty重试一定次数后调用System.exit(n)退出应用程序(二)

news2025/1/10 3:10:48

 ============================System.exit()方法=============================

原型:System.exit(int status)

其功能主要是调用Runtime.getRuntime().exit(status);

作用是终止当前正在运行的Java虚拟机,这个status表示退出的状态码,非零表示异常终止。(可以返回给其他进程的调用者一个调用的返回码,以根据返回码采取不同的策略。)

注意:不管status为何值程序都会退出,和return 相比有不同的是:return是回到上一层,而System.exit(status)是回到最上层。

System.exit(0): 

  • 正常退出,程序正常执行结束退出,Java GC进行垃圾回收,直接退出。
  • 在Swing开发中,一般用于Swing窗体关闭按钮。(重写windowClosing方法时调用System.exit(0)来终止程序,Window类的dispose()方法只是关闭窗口,并不会让程序退出)。

System.exit(1): 

  • 是非正常退出,就是说无论程序正在执行与否,都退出.
  • 如果为非0的话,如果这个方法被调用后,虚拟机已开始关闭序列如果关闭钩子正在运行,此方法将无限期阻塞。如果关将钩子运行完成,并且未调用的finalizers,在finalization-on-exit允许的情况下启动回收完成,虚拟机停止。
  • 一般在catch块中会使用(例如使用Apache的FTPClient类时,源码中推荐使用System.exit(1)告知连接失败),当程序会被脚本调用、父进程调用发生异常时需要通过System.exit(1)来告知操作失败,默认程序最终返回的值返是0,即然发生异常默认还是返回0,因此在这种情况下需要手工指定返回非零。

===============================Nettty代码===================================

Netty客户端:

package org.jy.sso.websocket.stomp.push.netty.chat.system.chatcenter;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateFormatUtils;
import org.jy.sso.websocket.stomp.push.netty.chat.system.chapter.handler.FirstClientSendMsgHandler;
import org.jy.sso.websocket.stomp.push.netty.chat.system.chatcommond.ChatRetryCommand;
import org.jy.sso.websocket.stomp.push.netty.chat.system.constant.ChatClientConstant;

import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * IM聊天系统客户端
 * <p>
 * 工具主要是封装了java.util.Random对象,提供了一些产生随机数或者随机字符串的方法。随机工具类是RandomUtil,里面的方法都是静态方法。
 */
@Slf4j
public class ChatCenterClient {
    public static final ConcurrentHashMap<Byte,Bootstrap> bootStrapMap = new ConcurrentHashMap();
    @SneakyThrows
    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        NioEventLoopGroup group = new NioEventLoopGroup();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel channel) {
                        // 在客户端添加一遍逻辑处理器,在客户建立连接成功后,向服务器端写数据
                        channel.pipeline().addLast(new FirstClientSendMsgHandler());
                    }
                });
        connect(bootstrap, ChatClientConstant.CHAT_SERVER_HOST_IP, ChatClientConstant.CHAT_SERVER_PORT, ChatClientConstant.CHAT_MAX_RETRY_NUM);
        // 重连指令与对应客户端启动的实例映射关系
        bootStrapMap.put(ChatRetryCommand.CHAT_RETRY_CONNECTION, bootstrap);
    }

    /**
     * @param bootstrap 客户端启动器
     * @param host      主机
     * @param port      端口
     * @param retryNum  指数退避重新连接的次数
     * @author yh19166
     * @deprecated 连接和重连机制,实现了指数退避重连
     */
    private static void connect(Bootstrap bootstrap, String host, int port, int retryNum) {
        bootstrap.connect(host, port).addListener(future -> {
            // 通过future.isSuccess() 判断是否连接成功
            if (future.isSuccess()) {
                System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " -->> 连接成功....");
            } else if (retryNum == ChatClientConstant.CHAT_INI_RETRY_NUM) {
                System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " -->> 重连次数已用完,放弃连接....");
                /**
                 * 原型:System.exit(int status)
                 *
                 * 其功能主要是调用Runtime.getRuntime().exit(status);
                 *
                 * 作用是终止当前正在运行的Java虚拟机,这个status表示退出的状态码,非零表示异常终止。(可以返回给其他进程的调用者一个调用的返回码,以根据返回码采取不同的策略。)
                 *
                 * 注意:不管status为何值程序都会退出,和return 相比有不同的是:return是回到上一层,而System.exit(status)是回到最上层。
                 *=======================================================================================================================================================
                 * System.exit(0):
                 *
                 * 正常退出,程序正常执行结束退出,Java GC进行垃圾回收,直接退出。
                 * 在Swing开发中,一般用于Swing窗体关闭按钮。(重写windowClosing方法时调用System.exit(0)来终止程序,Window类的dispose()方法只是关闭窗口,并不会让程序退出)。
                 * System.exit(1):
                 *
                 * 是非正常退出,就是说无论程序正在执行与否,都退出.
                 * 如果为非0的话,如果这个方法被调用后,虚拟机已开始关闭序列如果关闭钩子正在运行,此方法将无限期阻塞。如果关将钩子运行完成,并且未调用的finalizers,在finalization-on-exit允许的情况下启动回收完成,虚拟机停止。
                 * 一般在catch块中会使用(例如使用Apache的FTPClient类时,源码中推荐使用System.exit(1)告知连接失败),当程序会被脚本调用、父进程调用发生异常时需要通过System.exit(1)来告知操作失败,默认程序最终返回的值返是0,即然发生异常默认还是返回0,因此在这种情况下需要手工指定返回非零。
                 */
                System.exit(0);
            } else {
                // 第几次重连
                int order = (ChatClientConstant.CHAT_MAX_RETRY_NUM - retryNum) + ChatClientConstant.CHAT_STEP_RETRY_LENGTH;
                // 客户考虑重新连接的逻辑,分梯度连接......
                System.out.println("第 " + order + " 连接失败......");
                // 本次重连的间隔: 通过左移操作快速计算出重连时间间隔
                int delay = ChatClientConstant.CHAT_STEP_RETRY_LENGTH << order;
                System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " -->> 连接失败,第" + order + "次重新连接....");
                // 实现定时任务逻辑
                bootstrap.config().group().schedule(() -> connect(bootstrap, host, port, retryNum - ChatClientConstant.CHAT_STEP_RETRY_LENGTH), delay, TimeUnit.SECONDS);
            }
        });
    }

    /**
     * @param bootstrap 客户端启动类
     * @param host      主机
     * @param port      端口
     * @param retryNum  指数退避重新连接的次数
     * @author yh19166
     * @deprecated 连接和重连机制,实现了指数退避重连
     */
    @Deprecated
    public static void retryConnect(Bootstrap bootstrap, String host, int port, int retryNum) {
        bootstrap.connect(host, port).addListener(future -> {
            if (future.isSuccess()) {
                log.info("连接服务器成功!");
            } else if (retryNum == ChatClientConstant.CHAT_INI_RETRY_NUM) {
                log.error("重连次数已用完,放弃连接!");
                /**
                 * 原型:System.exit(int status)
                 *
                 * 其功能主要是调用Runtime.getRuntime().exit(status);
                 *
                 * 作用是终止当前正在运行的Java虚拟机,这个status表示退出的状态码,非零表示异常终止。(可以返回给其他进程的调用者一个调用的返回码,以根据返回码采取不同的策略。)
                 *
                 * 注意:不管status为何值程序都会退出,和return 相比有不同的是:return是回到上一层,而System.exit(status)是回到最上层。
                 *=======================================================================================================================================================
                 * System.exit(0):
                 *
                 * 正常退出,程序正常执行结束退出,Java GC进行垃圾回收,直接退出。
                 * 在Swing开发中,一般用于Swing窗体关闭按钮。(重写windowClosing方法时调用System.exit(0)来终止程序,Window类的dispose()方法只是关闭窗口,并不会让程序退出)。
                 * System.exit(1):
                 *
                 * 是非正常退出,就是说无论程序正在执行与否,都退出.
                 * 如果为非0的话,如果这个方法被调用后,虚拟机已开始关闭序列如果关闭钩子正在运行,此方法将无限期阻塞。如果关将钩子运行完成,并且未调用的finalizers,在finalization-on-exit允许的情况下启动回收完成,虚拟机停止。
                 * 一般在catch块中会使用(例如使用Apache的FTPClient类时,源码中推荐使用System.exit(1)告知连接失败),当程序会被脚本调用、父进程调用发生异常时需要通过System.exit(1)来告知操作失败,默认程序最终返回的值返是0,即然发生异常默认还是返回0,因此在这种情况下需要手工指定返回非零。
                 */
                System.exit(0);
            } else {
                // 第几次重连
                int order = (ChatClientConstant.CHAT_MAX_RETRY_NUM - retryNum) + ChatClientConstant.CHAT_STEP_RETRY_LENGTH;
                // 本次重连的间隔
                int delay = ChatClientConstant.CHAT_STEP_RETRY_LENGTH << order;
                log.error(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + ": 连接失败,第" + order + "次重新连接....");

                bootstrap.config().group().schedule(() -> connect(bootstrap, host, port, retryNum - ChatClientConstant.CHAT_STEP_RETRY_LENGTH), delay, TimeUnit.SECONDS);
            }
        });
    }
}

 代码中用到的常量类:

package org.jy.sso.websocket.stomp.push.netty.chat.system.constant;

public class ChatClientConstant {

    // 主机IP
    public static final String CHAT_SERVER_HOST_IP = "127.0.0.1";
    // 连接的端口
    public static final int CHAT_SERVER_PORT = 8000;
    // 最大重试次数
    public static final int CHAT_MAX_RETRY_NUM = 4;
    // 重试初始值
    public static final int CHAT_INI_RETRY_NUM = 0;
    // 步长
    public static final int CHAT_STEP_RETRY_LENGTH = 1;
}

 客户端处理器:

package org.jy.sso.websocket.stomp.push.netty.chat.system.chapter.handler;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateFormatUtils;
import org.jy.sso.websocket.stomp.push.netty.chat.system.chatcenter.ChatCenterClient;
import org.jy.sso.websocket.stomp.push.netty.chat.system.chatcommond.ChatRetryCommand;
import org.jy.sso.websocket.stomp.push.netty.chat.system.constant.ChatClientConstant;

import java.nio.charset.StandardCharsets;
import java.util.Date;

/**
 * 客户端向服务器端发送消息第一个处理器
 */
@Slf4j
public class FirstClientSendMsgHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("=========================向服务器端写数据============================");
        System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + ": 客户端写出数据");
        // 1.获取数据
        ByteBuf buffer = getByteBuf(ctx);
        // 2.写数据
        ctx.channel().writeAndFlush(buffer);
    }

    private ByteBuf getByteBuf(ChannelHandlerContext ctx) {
        // 1.获取二进制抽象 ByteBuf
        ByteBuf buffer = ctx.alloc().buffer();
        // 2.准备传递给服务器端的数据,并指定字符编码为UTF-8
        byte[] bytes = "你好,这是Netty客户端传递的数据".getBytes(StandardCharsets.UTF_8);
        // 3.填充数据到ByteBuf
        buffer.writeBytes(bytes);
        return buffer;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("=========================读取到服务器端的数据============================");
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " : 服务器端读到的客户端传递过来的数据 -> "
                + byteBuf.toString(StandardCharsets.UTF_8)); // 去掉这个编码转换结果为:
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    /**
     * 程序的健壮性考虑
     *
     * @param ctx 通道处理器上下文
     * @param cause 抛出的错误信息
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // 客户端没有正常退出导致的异常: 远程主机强迫关闭了一个现有的连接
        // 服务器端突然关闭,抛出该异常: 远程主机强迫关闭了一个现有的连接
        ctx.channel().flush();
        ctx.channel().closeFuture();
        log.info("FirstClientSendMsgHandler.exceptionCaught : [{}]", cause.getMessage());
        Bootstrap Bootstrap = ChatCenterClient.bootStrapMap.get(ChatRetryCommand.CHAT_RETRY_CONNECTION);
        ChatCenterClient.retryConnect(Bootstrap, ChatClientConstant.CHAT_SERVER_HOST_IP, ChatClientConstant.CHAT_SERVER_PORT, ChatClientConstant.CHAT_MAX_RETRY_NUM);
    }
}

==================================Netty服务器端==============================

package org.jy.sso.websocket.stomp.push.netty.chat.system.chatcenter;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.SneakyThrows;
import org.jy.sso.websocket.stomp.push.netty.chat.system.chapter.handler.FirstServerReceiveDataHandler;

/**
 * IM服务器端
 */
public class ChatCenterServer {
    @SneakyThrows
    public static void main(String[] args) {
        // 服务器端启动类
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        // boss主线程(父线程)
        NioEventLoopGroup bossLoopGroup = new NioEventLoopGroup();
        // 工作线程(子线程)
        NioEventLoopGroup workerLoopGroup = new NioEventLoopGroup();
        serverBootstrap // 父子线程建立组连接
                .group(bossLoopGroup, workerLoopGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) {
                        ch.pipeline().addLast(new FirstServerReceiveDataHandler());

                    }
                }).bind(8000).sync();
    }
}

 服务器端Pipeline对应的通道处理器handler:

package org.jy.sso.websocket.stomp.push.netty.chat.system.chapter.handler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.nio.charset.StandardCharsets;
import java.util.Date;

/**
 * 服务器端接收客户端数据的处理器:
 * 服务器端接收客户端数据
 * 响应客户端请求,并向客户端写数据
 */
@Slf4j
public class FirstServerReceiveDataHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object requestContent) {

        //接收客户端的数据逻辑
        System.out.println("============================接收客户端的数据=============================");
        ByteBuf byteBuf = (ByteBuf) requestContent;
        System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + " : 服务器端读到的客户端传递过来的数据 -> "
                + byteBuf.toString(StandardCharsets.UTF_8)); // 去掉这个编码转换结果为:
        System.out.println("============================向客户端写数据=============================");
        ByteBuf response = getByteBuf(ctx);
        ctx.channel().writeAndFlush(response);


    }

    /**
     * 向客户端写响应数据
     *
     * @param ctx 通道处理器上下文
     * @return {@link io.netty.buffer.ByteBuf}
     */
    private ByteBuf getByteBuf(ChannelHandlerContext ctx) {
        byte[] responseBytes = "你好,欢迎关注杨哥哥的微信公众号,<<财务自由耕耘者>>!".getBytes(StandardCharsets.UTF_8);
        ByteBuf buffer = ctx.alloc().buffer();
        buffer.writeBytes(responseBytes);
        return buffer;
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // 客户端未正常的关闭,抛出异常: 主机强迫关闭了一个现有的连接
        ctx.channel().flush();
        ctx.channel().closeFuture();
        log.info("exception: [{}]",cause.getMessage());
        // 可以考虑重启服务端,重新启动|重连区别
    }
}

测试效果日下:

====================== 先运行客户端代码============不运行服务器端代码=====================
20:04:33.435 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.tinyCacheSize: 512
20:04:33.435 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.smallCacheSize: 256
20:04:33.435 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.normalCacheSize: 64
20:04:33.435 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedBufferCapacity: 32768
20:04:33.435 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimInterval: 8192
20:04:33.448 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.allocator.type: pooled
20:04:33.448 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.threadLocalDirectBufferSize: 65536
20:04:33.448 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
第 1 连接失败......
2023-05-24 20:04:34 -->> 连接失败,第1次重新连接....
第 2 连接失败......
2023-05-24 20:04:37 -->> 连接失败,第2次重新连接....
第 3 连接失败......
2023-05-24 20:04:42 -->> 连接失败,第3次重新连接....
第 4 连接失败......
2023-05-24 20:04:51 -->> 连接失败,第4次重新连接....
2023-05-24 20:05:08 -->> 重连次数已用完,放弃连接....

Process finished with exit code 0
=============================客户端输出的日志=======================================
======先运行服务器端代码,在运行客户端代码,待客户端连接上服务端后,再关闭服务器端==============
20:27:31.730 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.normalCacheSize: 64
20:27:31.730 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedBufferCapacity: 32768
20:27:31.730 [main] DEBUG io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimInterval: 8192
20:27:31.748 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.allocator.type: pooled
20:27:31.748 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.threadLocalDirectBufferSize: 65536
20:27:31.748 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
2023-05-24 20:27:31 -->> 连接成功....
=========================向服务器端写数据============================
2023-05-24 20:27:31: 客户端写出数据
20:27:31.801 [nioEventLoopGroup-2-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxCapacityPerThread: 32768
20:27:31.801 [nioEventLoopGroup-2-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxSharedCapacityFactor: 2
20:27:31.801 [nioEventLoopGroup-2-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.linkCapacity: 16
20:27:31.809 [nioEventLoopGroup-2-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.ratio: 8
20:27:31.841 [nioEventLoopGroup-2-1] DEBUG io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.bytebuf.checkAccessible: true
20:27:31.841 [nioEventLoopGroup-2-1] DEBUG io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@5f1d79
=========================读取到服务器端的数据============================
2023-05-24 20:27:31 : 服务器端读到的客户端传递过来的数据 -> 你好,欢迎关注杨哥哥的微信公众号,<<财务自由耕耘者>>!
20:27:37.561 [nioEventLoopGroup-2-1] INFO org.jy.sso.websocket.stomp.push.netty.chat.system.chapter.handler.FirstClientSendMsgHandler - FirstClientSendMsgHandler.exceptionCaught : [远程主机强迫关闭了一个现有的连接。]
20:27:38.569 [nioEventLoopGroup-2-2] ERROR org.jy.sso.websocket.stomp.push.netty.chat.system.chatcenter.ChatCenterClient - 2023-05-24 20:27:38: 连接失败,第1次重新连接....
第 2 连接失败......
2023-05-24 20:27:41 -->> 连接失败,第2次重新连接....
第 3 连接失败......
2023-05-24 20:27:46 -->> 连接失败,第3次重新连接....
第 4 连接失败......
2023-05-24 20:27:55 -->> 连接失败,第4次重新连接....
2023-05-24 20:28:12 -->> 重连次数已用完,放弃连接....

Process finished with exit code 0
===============================客户端输出的日志==============================

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RES 新的数据集 Advancing Referring Expression Segmentation Beyond Single Image 论文笔记

RES 新的数据集 Advancing Referring Expression Segmentation Beyond Single Image 论文笔记 一、Abstract二、引言三、相关工作3.1 Referring Expression Segmentation (RES)3.2 CoSalient Object Detection (CoSOD) 四、提出的方法4.1 概述文本 & 图像编码器TQM & H…

OpenStreetMap实战

介绍 OpenStreetMap&#xff08;OSM&#xff09;是一个由志愿者创建并维护的免费和开源的地图数据库。其目的是为全球任何人提供可自由使用、编辑和分发的地图数据。OpenStreetMap数据库中的地理要素包括道路、建筑、河流、森林、山脉、公共设施等。由于OpenStreetMap是开放的…

数据结构初阶 —— 二叉树链式结构

目录 一&#xff0c;二叉树链式结构 二&#xff0c;二叉树的遍历&#xff08;四种&#xff09; 前序遍历 中序遍历 后序遍历 层序遍历 三&#xff0c;二叉树接口 四&#xff0c;试题 一&#xff0c;二叉树链式结构 普通二叉树的增删查改&#xff0c;意义不大&#xff1b…

JavaScript基础扫盲

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 本篇文章为大家带来JavaScript的学习&#xff0c;一图胜千言~~~ 目录 文章目录 1.1 JavaScript (简称 JS) 1.2 JavaScript发展历史 1.3 JavaScript运行过程 二、JavaScript的基础语法 2.1 …

Linux内核源码分析-进程调度(五)-组调度

出现的背景 总结来说是希望不同分组的任务在高负载下能分配可控比例的CPU资源。为什么会有这个需求呢&#xff0c;假设多用户计算机系统每个用户的所有任务划分到一个分组中&#xff0c;A用户90个任务&#xff0c;而B用户只有10个任务&#xff08;这100个任务假设都是优先级一…

物联网手势控制小车所遇问题与解决方案

LCD1602无法显示问题 问题描述&#xff1a;按照开源社区教程完成LCD1602驱动显示程序的编写&#xff0c;成功点亮屏幕&#xff0c;开启背光&#xff0c;但无法观察到显示数据。 分析过程与解决方案&#xff1a; 1.是否IIC地址不对 使用以下代码扫描IIC总线上的设备&#xf…

Go学习圣经:队列削峰+批量写入 超高并发原理和实操

说在前面&#xff1a; 本文是《Go学习圣经》 的第二部分。 第一部分请参见&#xff1a;Go学习圣经&#xff1a;0基础精通GO开发与高并发架构&#xff08;1&#xff09; 现在拿到offer超级难&#xff0c;甚至连面试电话&#xff0c;一个都搞不到。 尼恩的技术社群中&#xf…

K近邻算法实现红酒数据集分类

目录 1. 作者介绍2. K近邻算法介绍2.1 K基本原理2.2 算法优缺点 3. KNN红酒数据集分类实验3.1 获取红酒数据集3.2 KNN算法3.3 完整代码 4. 问题分析参考链接&#xff08;可供参考的链接和引用文献&#xff09; 1. 作者介绍 路治东&#xff0c;男&#xff0c;西安工程大学电子信…

面试问题汇总

最近面试了几家公司&#xff0c;对问到的问题汇总一下。 Unity 是左手坐标系还是右手坐标系? 这个题靠记忆答的答错了&#xff0c;是左手坐标系。 大拇指指的方向是X轴&#xff0c;食指指的方向是Y轴方向&#xff0c;中指指的方向Z轴方向。 场景中游戏物体Activity为false,G…

C语言字符串函数和内存函数的介绍与模拟实现

0.前言 C语言中对字符和字符串的处理很是频繁&#xff0c;但是C语言本身是没有字符串类型的&#xff0c;字符串通常放在 常量字符串 中或者 字符数组 中。 字符串常量 适用于那些对它不做修改的字符串函数. 1.字符串函数介绍与模拟实现 C语言本身就带有一些库函数&#xff0c;所…

研发工程师玩转Kubernetes——CPU配额

在一个Pod中&#xff0c;可以有多个容器&#xff0c;比如一个主要业务容器和若干辅助业务容器。如果辅助业务容器内程序有问题&#xff0c;导致占用了大量的CPU资源&#xff0c;进而影响了主要业务容器的执行效率&#xff0c;那就需要进行干涉了。本节我们将使用“资源配额”来…

Edgedetect

边缘检测&#xff0c;检测上升沿 对于 8 位矢量中的每个位&#xff0c;检测输入信号何时从一个时钟周期中的 0 变为下一个时钟周期的 1&#xff08;类似于正边沿检测&#xff09;。输出位应在发生 0 到 1 转换后设置周期。 以下是一些示例。为清楚起见&#xff0c;in[1] 和 pe…

Jenkins+GitLab+Docker搭建前端自动化构建镜像容器部署(无本地证书,映射版本)

前言 &#x1f680; 需提前安装环境及知识点&#xff1a; 1、Docker搭建及基础操作 2、DockerFile文件描述 3、Jenkins搭建及基础点 &#x1f680; 目的&#xff1a; 将我们的前端项目打包成一个镜像容器并自动发布部署&#xff0c;可供随时pull访问 一、手动部署镜像及容器 1…

【Linux】线程分离 | 线程库 | C++调用线程 | 线程局部存储

文章目录 1. 线程分离1. 为什么要线程分离&#xff1f;2. 具体使用3. 为什么有时候分离在调用join 会正常运行&#xff1f; 2. 如何理解线程库&#xff1f;如何理解 先描述 在组织&#xff1f; 3. C中使用多线程4. 线程局部存储局部变量全局变量 1. 线程分离 1. 为什么要线程分…

服务器虚拟化部署

服务器虚拟化部署 1、背景2、目的3、环境4、部署4.1、部署VMware ESXi4.1.1、准备工作4.1.2、部署ESXi4.1.3、配置ESXi4.1.4 、部署虚拟机 1、背景 项目上利旧9台服务器&#xff0c;项目需要使用15台服务器&#xff0c;外购已经没有项目硬件采购预算&#xff0c;只能从目前的…

自定义HikariCP连接池

文章目录 一、简介1、概述2、地址 二、配置参数1、Hikari原生参数2、Springboot中参数 三、springboot中使用四、自定义数据源1、各模块2、完整代码3、多数据源 五、多数据源dynamic中使用1、简介2、引入依赖3、参数配置 六、XMind整理 一、简介 1、概述 官方解释&#xff1a…

zabbix 自动发现与自动注册、部署 zabbix 代理服务器及部署 Zabbix 高可用集群

目录 一、zabbix 自动发现二、zabbix 自动注册&#xff08;对于 agent2 是主动模式&#xff09;三、部署 zabbix 代理服务器四、部署 Zabbix 高可用集群五、Zabbix 监控 Windows 系统六、Zabbix 监控 java 应用七、Zabbix 监控 SNMP 一、zabbix 自动发现 zabbix 自动发现&…

Nautilus Chain开启全球行,普及Layer3概念加速其采用

在去年&#xff0c;在 2022 年&#xff0c;Vitalik 进一步提出了 Layer3 的概念与早期形态&#xff0c;期盼弥补目前链体系存在的不足&#xff0c;并为 Layer3 提出了三大目标&#xff0c;即Layer2 用于扩展&#xff0c;Layer3 用于定制功能&#xff0c;如隐私&#xff1b;Laye…

【C++】哈希表特性总结及unordered_map和unordered_set的模拟实现

✍作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;C 文章目录 前言一、哈希表的特性 - 哈希函数和哈希冲突1 哈希函数2. 哈希冲突 二、闭散列的实现 -- 开放地址法1. 定义数据结构2.insert()3.Find()4. Erase()5.仿函数处理key值不能取模无法映射 --- BKDRHash 三、开…

【Linux系列P4】Linux需要什么?编辑器?软件包?一文帮你了解掌握 [yum][vim]———基础开发工具篇

前言 大家好&#xff0c;这里是YY的Linux系列part4&#xff1b;本章主要内容面向接触过Linux的老铁&#xff0c;主要内容含【学习yum工具&#xff0c;进行软件安装】【拓展yum源安装】【掌握vim编辑器使用&#xff0c;基本命令】【命令集】【懒人配置文件安装教程】 在下一章节…