SOFAJRaft源码阅读-ShutdownHook如何优雅的停机

Java程序经常会遇到进程挂掉的情况,一些状态没有正确的保存下来,这时候就需要在JVM关掉的时候执行一些清理现场的代码。JAVA中的ShutdownHook提供了比较好的方案。而在SOFAJRaft-example模块的CounterServer-main方法中就使用了shutdownHook实现优雅停机。
@Author:Akai-yuan
@更新时间:2023/1/25

1.触发场景与失效场景

JDK提供了Java.Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子这个钩子可以在以下几种场景中被调用:

  1. 程序正常退出
  2. 执行了System.exit()方法
  3. 终端使用Ctrl+C触发的中断
  4. 系统关闭
  5. OutOfMemory宕机
  6. 使用Kill pid命令干掉进程(使用 **kill -9 pid **是不会被调用的)

以下几种情况中是无法被调用的:

  1. 通过kill -9命令杀死进程——所以kill -9一定要慎用;
  2. 程序中执行了Runtime.getRuntime().halt()方法;
  3. 操作系统突然崩溃,或机器掉电(用电设备因断电、失电、或电的质量达不到要求而不能正常工作)。

2.addShutdownHook方法简述

Runtime.getRuntime().addShutdownHook(shutdownHook);

该方法指,在JVM中增加一个关闭的钩子,当JVM关闭的时候,会执行系统中已经设置的所有通过方法addShutdownHook添加的钩子,当系统执行完这些钩子后,JVM才会关闭。所以这些钩子可以在JVM关闭的时候进行内存清理、对象销毁、关闭连接等操作。

3.SOFAJRaft中钩子函数的实现

通过反射获取到grpcServer实例的shutdown方法和awaitTerminationLimit方法,并添加到钩子函数当中

public static void blockUntilShutdown() {
        if (rpcServer == null) {
            return;
        }
        //当RpcFactoryHelper中维护的工厂类型是GrpcRaftRpcFactory时进入if条件内部
        if ("com.alipay.sofa.jraft.rpc.impl.GrpcRaftRpcFactory".equals(RpcFactoryHelper.rpcFactory().getClass()
            .getName())) {
            try {
                //反射获取grpcServer中维护的(io.grpc包下的)server实例
                Method getServer = rpcServer.getClass().getMethod("getServer");
                Object grpcServer = getServer.invoke(rpcServer);
                //反射获取server实例的shutdown方法和awaitTerminationLimit方法
                Method shutdown = grpcServer.getClass().getMethod("shutdown");
                Method awaitTerminationLimit = grpcServer.getClass().getMethod("awaitTermination", long.class,
                    TimeUnit.class);
            	//添加一个shutdownHook线程执行方法
                Runtime.getRuntime().addShutdownHook(new Thread() {
                    @Override
                    public void run() {
                        try {
                            shutdown.invoke(grpcServer);
                            awaitTerminationLimit.invoke(grpcServer, 30, TimeUnit.SECONDS);
                        } catch (Exception e) {
                            // Use stderr here since the logger may have been reset by its JVM shutdown hook.
                            e.printStackTrace(System.err);
                        }
                    }
                });
                //执行awaitTermination方法
                Method awaitTermination = grpcServer.getClass().getMethod("awaitTermination");
                awaitTermination.invoke(grpcServer);
            } catch (Exception e) {
                LOG.error("Failed to block grpc server", e);
            }
        }
    }

4.grpc中的shutdown方法

GrpcServer下的shutdown方法与本文的钩子函数无关,此处再对比分析一下GrpcServer的shutdown方法。

    public void shutdown() {
        //CAS
        //当且仅当期待值为true时(与当前AtomicBoolean类型的started一致),设置为false关闭
        if (!this.started.compareAndSet(true, false)) {
            return;
        }
        ExecutorServiceHelper.shutdownAndAwaitTermination(this.defaultExecutor);
        GrpcServerHelper.shutdownAndAwaitTermination(this.server);
    }

ExecutorServiceHelper#shutdownAndAwaitTermination:
我们可以发现实际上就是在执行ExecutorService 中 的shutdown()、shutdownNow()、awaitTermination() 方法,那么我们来区别以下这几个方法

public static boolean shutdownAndAwaitTermination(final ExecutorService pool, final long timeoutMillis) {
        if (pool == null) {
            return true;
        }
        // 禁止提交新任务
        pool.shutdown();
        final TimeUnit unit = TimeUnit.MILLISECONDS;
        final long phaseOne = timeoutMillis / 5;
        try {
            // 等待一段时间以终止现有任务
            if (pool.awaitTermination(phaseOne, unit)) {
                return true;
            }
            pool.shutdownNow();
            // 等待一段时间,等待任务响应被取消
            if (pool.awaitTermination(timeoutMillis - phaseOne, unit)) {
                return true;
            }
            LOG.warn("Fail to shutdown pool: {}.", pool);
        } catch (final InterruptedException e) {
            // (Re-)cancel if current thread also interrupted
            pool.shutdownNow();
            // preserve interrupt status
            Thread.currentThread().interrupt();
        }
        return false;
    }

  1. shutdown():停止接收新任务,原来的任务继续执行

1、停止接收新的submit的任务;
2、已经提交的任务(包括正在跑的和队列中等待的),会继续执行完成;
3、等到第2步完成后,才真正停止;


  1. shutdownNow():停止接收新任务,原来的任务停止执行

1、跟 shutdown() 一样,先停止接收新submit的任务;
2、忽略队列里等待的任务;
3、尝试将正在执行的任务interrupt中断;
4、返回未执行的任务列表;
说明:
它试图终止线程的方法是通过调用 Thread.interrupt() 方法来实现的,这种方法的作用有限,如果线程中没有sleep 、wait、Condition、定时锁等应用, interrupt() 方法是无法中断当前的线程的。
所以,shutdownNow() 并不代表线程池就一定立即就能退出,它也可能必须要等待所有正在执行的任务都执行完成了才能退出。但是大多数时候是能立即退出的。


  1. awaitTermination(long timeOut, TimeUnit unit):当前线程阻塞

当前线程阻塞,直到:

  • 等所有已提交的任务(包括正在跑的和队列中等待的)执行完;
  • 或者 等超时时间到了(timeout 和 TimeUnit设定的时间);
  • 或者 线程被中断,抛出InterruptedException

然后会监测 ExecutorService 是否已经关闭,返回true(shutdown请求后所有任务执行完毕)或false(已超时)

GrpcServerHelper#shutdownAndAwaitTermination
与ExecutorServiceHelper类中的shutdownAndAwaitTermination方法类似的,该方法将优雅的关闭grpcServer.

public static boolean shutdownAndAwaitTermination(final Server server, final long timeoutMillis) {
        if (server == null) {
            return true;
        }
        // disable new tasks from being submitted
        server.shutdown();
        final TimeUnit unit = TimeUnit.MILLISECONDS;
        final long phaseOne = timeoutMillis / 5;
        try {
            // wait a while for existing tasks to terminate
            if (server.awaitTermination(phaseOne, unit)) {
                return true;
            }
            server.shutdownNow();
            // wait a while for tasks to respond to being cancelled
            if (server.awaitTermination(timeoutMillis - phaseOne, unit)) {
                return true;
            }
            LOG.warn("Fail to shutdown grpc server: {}.", server);
        } catch (final InterruptedException e) {
            // (Re-)cancel if current thread also interrupted
            server.shutdownNow();
            // 保持中断状态
            Thread.currentThread().interrupt();
        }
        return false;
    }
本文转载于网络 如有侵权请联系删除

相关文章

  • mac视频格式转换器Wondershare UniConverter for Mac

    WondershareUniConverterforMac是Macos上一款全能视频格式转换器,您可以随时随地观看、下载、编辑、转换、刻录视频,兼具网络视频下载,视频剪辑及DVD刻录等多功能于一身。立即下载:https://www.macw.com/mac/2469.html?id=MjU2NjEmXyYyNy4xODYuMTI0LjQ%3D全新功能强大的视频格式转换几乎涵盖了所有视频格式和音频格式,只需要将音视频或文件夹拖拽到窗口中即可快速完成转换,可以选择预设的格式,可以自定义格式,设置分辨率、字幕,可以一键进行视频压缩。高速下载在线视频支持Youtube、blibili等1000多个在线视频网站的视频下载,可以选择分辨率清晰度,下载速度非常快!IOS/DVD刻录功能强大的UniConverterDVD工具包,可帮助您轻松创建和编辑DVD文件,立享蓝光体验。传输文件到手机可以将照片、文件、视频、音乐传输到手机,很方便。屏幕录像机支持全屏录像、区域录像以及窗口录像三种模式,支持记录鼠标,设置帧率,设置画面质量,播放鼠标单击声音,麦克风录制等,功能很强大。图片格式转换器可转换图片格式,

  • Linux之find xargs

    exec的问题参数太长在使用find命令的-exec选项处理匹配到的文件时,find命令将所有匹配到的文件一起传递给exec执行。但有些系统对能够传递给exec的命令长度有限制,这样在find命令运行几分钟之后,就会出现溢出错误argumentlinetoolong。错误信息通常是“参数列太长”或“参数列溢出”。这就是xargs命令的用处所在,特别是与find命令一起使用。find命令把匹配到的文件传递给xargs命令,而xargs命令每次只获取一部分文件而不是全部,不像-exec选项那样。这样它可以先处理最先获取的一部分文件,然后是下一批,并如此继续下去。进程过多在有些系统中,使用-exec选项会为处理每一个匹配到的文件而发起一个相应的进程,并非将匹配到的文件全部作为参数一次执行;这样在有些情况下就会出现进程过多,系统性能下降的问题,因而效率不高;而使用xargs命令则只有一个进程。另外,在使用xargs命令时,究竟是一次获取所有的参数,还是分批取得参数,以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。查询当前目录下所有权限是777的文件>find

  • 百度连接服务,不只是流量生意

    4月26日,在2021万象大会上,百度App进行品牌升级,从2017年沿用至今的Slogan“有事搜一搜没事看一看”变为“百度一下,生活更好”。此前的slogan体现出百度在相当长一个阶段内的“信息+知识”战略,“百度一下,生活更好”的新Slogan,则反映出百度移动生态下一阶段发展的战略方向。互联网进入存量阶段,超级App们在生态趋于成熟后,都在卯着劲深耕细作挖存量。百度App的解法是“服务化、人格化”,一年下来外界明显感知到,百度App在产品、运营、商业层面均在加强人格化和强化服务属性,生态充满“人气”,让用户“生活更好”的价值已在显现。现在百度App确定“生活更好”的品牌主张,也意味着百度移动生态将深化服务化与人格化“两化战略”落地,一方面“以人为本”,使人与人的连接规模更大,互动效率更高;另一方面“服务到位”,基于智能搜索的“搜索即感知,搜索即服务”能力,给用户、创作者、商家等生态各方构建更加繁荣的服务生态。新阶段,新战略,新起点已有多家头部互联网企业在焕新品牌,与之相随的是战略全面升级。“百度一下,生活更好”,是百度这一已有20多年发展历程的互联网巨头,跟信息与知识的内容时代

  • CMake入门实战——单个源文件

    什么是CMake你或许听过好几种Make工具,例如GNUMake,QT的qmake,微软的MSnmake,BSDMake(pmake),Makepp,等等。这些Make工具遵循着不同的规范和标准,所执行的Makefile格式也千差万别。这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的Make工具,就得为每一种标准写一次Makefile,这将是一件让人抓狂的工作。 CMake就是针对上面问题所设计的工具:它首先允许开发者编写一种平台无关的CMakeList.txt文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化Makefile和工程文件,如Unix的Makefile或Windows的VisualStudio工程。从而做到“Writeonce,runeverywhere”。显然,CMake是一个比上述几种make更高级的编译配置工具。一些使用CMake作为项目架构系统的知名开源项目有VTK、ITK、KDE、OpenCV、OSG等。 在linux平台下使用CMake生成Makefile并编译的流程如下:编写CMake配置文件C

  • 序列作为主键使用的原理、优缺点讨论

    这几天和同事一直在讨论关于表设计中主键选择的问题,用sequence作为主键究竟有什么好处,又有什么缺点,尤其是有些事务场景上下文需要用到创建的序列值,如何用?其实我想说的是,可能只是一个很简单的概念,可能深入理解,还是有很多未知的知识,当然也就可能会有一些容易忽略但又可能很关键的坑,只有碰了才知道。。。以下是总结摘要,如有疏漏,还请过路的各位大侠赐教。1、首先说下seq.nextval主要有以下两种使用场景: (1). 如果一个事务中只是INSERT时需要序列,其他地方不会需要这个序列,那么只需要在INSERT ... VALUES (seq.nextval ...)语句中使用即可。 (2). 如果一个事务中INSERT一张表后,还需要插入时的主键ID值,作为外键插入其他表,那么就需要在INSERT第一张表前使用select seq.nextval from dual提前获取可用的ID保存到一个变量中,为后面使用。 2、其次可以简单说下调用序列的原理,只有理解了序列的原理,才能有助于我们知道如何正确使用序列。 使用序列时Oracle内部大体是按照如下步骤进行: (1). 一个序列会

  • LAMP搭建wordpress博客

    LAMP(LINUX7.3+APACHE2.4+MYSQL5.6+PHP7.1)搭建wordpress博客:确认httpd服务有没有开启psaux|grephttpd /usr/local/apache2.4/bin/apachectlstart 启动服务 psaux|grephttpd 再次查看服务复制启动mysql服务psaux|grepmysql servicemysqlstart复制配置域名vim/usr/local/apache2.4/conf/extra/httpd-vhosts.conf复制<VirtualHost*:80> ServerNamewww.haha.com DocumentRoot"/data/wwwroot/www.haha.com" </VirtualHost> 只需要配置一个域名,一个站点的目录即可!复制测试,重载/usr/local/apache2.4/bin/apachectl-t复制/usr/local/apache2.4/bin/apachectlgraceful AH00112:Warni

  • 八、线程和进程 什么是线程(thread)?什么是进程(process)? 线程和进程的区别?Python GIL(Global Interpreter Lock)全局解释器锁

    什么是线程(thread)?线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。一个线程是一个执行上下文,它是一个CPU需要执行一系列指令的所有信息。 假设你正在读一本书,你现在想休息一下,但是你希望能够回来,从你停止的地方继续阅读。实现这一目标的一种方法是记下页码、行号和字号。所以你读一本书的执行上下文是这三个数字。 如果你有一个室友,而且她使用的是同样的技术,她可以在你不用的时候拿着书,然后从她停止的地方继续阅读。然后你可以把它拿回来,从你所在的地方重新开始。 线程的工作方式相同。一个CPU给你的错觉是它同时在做多个计算。它通过在每个计算上花费一点时间。它可以这样做,因为它对每个计算都有一个执行上下文。就像你可以和你的朋友分享一本书一样,许多任务可以共享一个CPU。 在技术层面上,执行上下文(因此是一个线程)由CPU寄存器的值组成。 最后:线程与进程不同。线程是执行的上下文,而进程是与计算相关的一堆资源。一个进程可以有一个或多个线程。 说明:与进程相关

  • 每天一个 HTTP 状态码 204

    204NoContent 204NoContent表示服务器成功地处理了客户端的请求,但是没有任何要响应的内容。API设计上,在用PUT请求更新某个资源成功后,后端可以在HTTP响应头部指示一些更新的相关信息,确实没必要再返回任何响应内容,这就是204NoContent常见的使用场景之一。 某种程度上,可以认为以下两种响应是等价的: HTTP/2204NoContent 复制 HTTP/2200OK Content-Length:0 复制 显然地,第一种看起来更简洁高效。所以实践中,更多开发者倾向于使用第一种响应。 参考 ListofHTTPstatuscodes HTTPresponsestatuscodes 204NoContent 文完撒花?!感谢观看?!

  • ML.NET机器学习、API容器化与Azure DevOps实践(三):RESTful API

    通过上文所述案例,我们已经选择了最优回归算法来预测学生的综合成绩,并且完成了基于训练数据集的预测模型训练。从实现上,训练好的模型被保存成一个ZIP文件,以便在其它项目中直接调用以完成机器学习的实践场景。在本文中,我将介绍如何在ASP.NETCore中使用这个ZIP文件,以提供用于学生成绩预测的RESTfulAPI。将模型文件保存到AzureBlobStorage中我们已经得到了经过ML.NET训练好的模型数据文件,也就是一个ZIP文件,在开发的RESTfulAPI中,需要读入这个文件以便实现预测功能。于是,ZIP文件保存在何处就成为了我们首要解决的问题。在开发环境,我们可以将ZIP文件保存在ASP.NETCore的运行目录中,可是,开发好的RESTfulAPI最终还是要部署到生产环境,这种部署有可能是单节点的,也有可能是位于负载均衡服务器后端的多节点部署,而且模型文件也会随着训练数据集的增加或变化进行增量式更新,因此,依赖于部署环境的本地文件系统并不是一个好的做法。因此,我选择将模型文件保存在AzureBlobStorage中。注意:为了防止在开发调试阶段过多使用AzureBlobSt

  • C# CreateParams的使用(解决闪屏问题)

    最近在做数据筛选界面,左右数据联动,但窗体数据刷新严重,但以前有个相同的项目没此问题,通过代码比较,是缺少闪屏处理。 参考文章: (1)C#CreateParams的使用(解决闪屏问题) (2)https://www.cnblogs.com/Alex1994/p/10393845.html (3)https://www.javazxz.com/thread-3804-1-1.html

  • 最小一乘法的一种数值算法?

    jhd牛逼 考虑最小一乘法,那么就是要求出最优直线的\(k,b\)值。 结论,存在最优拟合直线经过至少两个输入点,不过对这个算法没啥用就对了。 如果\(k\)固定,那么\(b\)是相对纵坐标的中位数。 如果\(b\)固定,那么\(k\)是相对斜率的中位数。 考虑三分\(k\), 在一个固定的\(k\)下 \(nth\_element\)找出相对纵坐标的中位数,然后就得到了一个\(O(nlogC)\)的优秀做法。 但是为什么可以三分斜率呢?求大佬指点。

  • Micropython教程之TPYBoard DIY超声波测距仪实例演示

    1.实验目的 1.学习在PC机系统中扩展简单I/O?接口的方法。2.进一步学习编制数据输出程序的设计方法。3.学习超声波模块的测距原理。4.学习LCD5110接线方法5.学习TPYboard控制超声波模块测距。(萝卜学科编程教育tpyboard。com) 2.所需元器件 超声波模块一个TPYBoard板子一块5110LCD显示屏一个数据线一条杜邦线若干 3.超声波模块工作原理 (1)采用IO口TRIG触发测距,给最少10us的高电平信呈。(2)模块自动发送8个40khz的方波,自动检测是否有信号返回。(3)有信号返回,通过IO口ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2。如下图接线,VCC供5V电源,GND为地线,TRIG触发控制信号输入,ECHO回响信号输出等四个接口端。。(萝卜学科编程教育tpyboard。com)   4.控制5110显示屏显示6x8字符 先看一下LCD5110针脚含义吧(注意:LCD5110的针脚有些不一样的)TPYBoard的针脚与5110的针脚对应关系如下: TPYBoa

  • 当spring 容器初始化完成后执行某个方法

      在做web项目开发中,尤其是企业级应用开发的时候,往往会在工程启动的时候做许多的前置检查。比如检查是否使用了我们组禁止使用的Mysql的group_concat函数,如果使用了项目就不能启动,并指出哪个文件的xml文件使用了这个函数。而在Spring的web项目中,我们可以介入Spring的启动过程。我们希望在Spring容器将所有的Bean都初始化完成之后,做一些操作,这个时候我们就可以实现一个接口:   方法一: 1packagecom.leadsoft.test.executor.processor 2publicclassInstantiationTracingBeanPostProcessor 3implementsApplicationListener<ContextRefreshedEvent>{ 4@Override 5publicvoidonApplicationEvent(ContextRefreshedEventevent){ 6//需要执行的逻辑代码,当spring容器初始化完成后就会执行该方法。 7} 8}复制   同时在Spring的配置

  • 软工作业PSP与单元测试训练 15100360

    任务说明(二选一):   我选择实现模块判断传入的电子邮箱账号的正确性。 实现要求:   一、实现功能模块:通过正则表达式进行简单的判断;   二、 publicclassTest{ publicstaticvoidmain(Stringarg[]){ Scannerstr=newScanner(System.in); Stringemail=str.nextLine(); while(true) { if(Test.checkEmail(email)) { System.out.println(email+"是合法的邮箱名。"); break; } else { System.out.println(email+"不是合法的邮箱名。"); break; } } } publicstaticbooleancheckEmail(Stringemail){ Stringpattern="\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"; returnPattern.matches(pattern,email); } }复制 &nb

  • [网鼎杯 2018]Fakebook

    [网鼎杯2018]Fakebook 打开网站发现是一个登录界面,还可以任意注册账号 先随便注册一个账号 然后点击了一下注册后的名字 出现了这个界面,好似没什么用处,但仔细看了一下网址http://1.14.71.254:28653/view.php?no=1,这个no=1,好像可以进行注入 说明了字段数为4 查找回显点是,被提示错误,应该是什么东西被过滤了,可以用union/**/select进行绕过 发现回显点为2 查找出数据库名为fakebook 表名为users 有这么多的列名,就一个一个的试,发现在data列里面有点不对 显示出来的是经过序列化后的东西 这就不知道咋整了,直接搜wp 看到了两种解法,简答的一直就是直接用load_file()函数,直接读取flag.php文件得到flag 还有一种就是根据下载robots.txt文件,查看页面的源码,通过代码审计,构造payloado=-1union/**/select1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:0;s:4:"blog";s:

  • Head First 设计模式之适配器模式与外观模式

    HeadFirst设计模式之适配器模式与外观模式 前言: 之前讲过装饰者模式,将对象包装起来并赋予新的职责,这一章我们也会将对象进行包装,只不过是让它们看起来不像自己而像是别的东西。这样就可以在设计中将类的接口转化为想要的接口,以实现同的接口,此外还将讲述另一个模式,将对象包装起来以简化接口。 1.   适配器简介 1.1面向对象的适配器 真实世界的适配器比如位于美式插头和欧式插座之间的交流电适配器。面向对象的适配器是什么呢? 面向对象的适配器是将一个接口转化成另一个接口,以符合客户的期望。 例如已有的一个软件系统,希望它能和一个新的厂商类库搭配使用,但是这个厂商设计出来的接口不同于旧的接口,而你又不想改变现有的代码,所以这个时候就需要一个适配器来完成现有系统和新的厂商类库的对接。 1.2使用中的适配器 我们在策略模式里举例讲的鸭子。看一个简化版的示例。 1.2.1鸭子接口   publicinterfaceDuck { voidQuack();//鸭子叫 voidFly();//鸭子飞 }复制   1.2.2鸭子子类(绿头鸭)实现 &

  • DAU新解

    写在回归之时 --------------------------- 抱歉,已经超过三年没有回到这里了。 浮躁,虚荣,一颗心没有落到地上,也没有好好总结一下自己。怀念最开始那个时候的状态,安静的做点事情,没有那么多关于管理,开会,PPT,甚至领略战略意图的繁琐。不是这些不好,而是有更重要的事情要组完成。Smallisbeautiful。越来越多的事情,越来越多的时间消费,失去了奋斗精神,失去了激情。我不相信这是因为人多了,一切就要随着变,我希望传统不变。 我想去研究一点东西,做一点事情,一点可以一直做下去的事情,这几年,经历了很多的主题,战略,每一个都没做踏实,但又幸好走过来了,可是自己,带着伙伴,却变得有些缺少狼性,缺少信心,为什么?也许是缺少坚实的基础和底气。 我想踏实认真的做一件事,哪怕它失败了,至少我是完整的经历了。 我已经没了最开始的激情,多了很多的抱怨,痛苦,诉说自己种种无法释怀的事情,种种无法让人理解的事情,其实到头发现,没人会在意,自己不去改变,什么也不会变化。 所以,现在需要给自己一个重新来过的机会。做好一件事。 以前做过游戏,做过金融,做过培训,做过广告,当下在做零

  • linux基本权限和归属、附加权限控制

    一、基本权限和归属 1.访问权限 读取:允许查看、显示目录列表 写入:允许修改,允许在目录中新建、移动、删除文件或子目录 可执行:允许运行程序、切换目录 2.查看文件的权限 #ls-linstall.log -|rw-|r--|r--1 root root 26195Dec1710:42 install.log ①②③④⑤ ⑥  ⑦   ⑧     ⑨         ⑩ ①.文件类型 -代表普通文件 d代表目录 l代表连接 ②.rw-:代表文件所有者的权限(u) r=读=4 w=写=2 x=执行=1 ③.r--:代表文件所属组的权限(g) r=读=4 w=写=2 x=执行=1 ④.r--:其他用户的权限(o) r=读=4 w=写=2 x=执行=1 a=ugo ⑤.文件 硬链接数    目录 该目录下

  • 【虚拟声卡】Winkawaks报错Directsound不能初始化

    原因 电脑没有声卡,导致打开模拟器失败 处理方式 安装一个虚拟声卡 下载地址 https://www.onlinedown.net/soft/632816.htm 安装步骤 虚拟声卡驱动VirtualAudioCable安装步骤       1、在本站下载虚拟声卡驱动VirtualAudioCable软件包,解压后运行exe安装文件,点击安装       2、正在安装中,耐心等待安装完成       3、虚拟声卡驱动VirtualAudioCable安装完成,点击确定后就可以使用了 虚拟声卡驱动VirtualAudioCable使用方法       1、安装虚拟声卡驱动VirtualAudioCable软件       2、右键单击电脑右下角音量控制图标,在录音设备

  • 网页响应慢,waiting(TTFB)时间过长,接口返回耗时,数据库占用CPU 90%以上

    记一次网页响应慢,waiting(TTFB)时间过长,接口返回耗时,数据库占用CPU90%以上问题排查 症状:H5页面打开白板,几十秒后出现页面,调试跟踪访问接口waiting(TTFB:全称 TimeToFirstByte,是指网络请求被发起到从服务器接收到第一个字节的这段时间,它包含了TCP 连接时间、发送 HTTP 请求时间和获得响应消息第一个字节的时间)时间过长,查看服务器资源占用,SqlServer占用CPU90%以上     网上查询相关解决办法:1.网络原因,使用CDN。2.网页去访问了其他插件/网络地址(百度翻译等)。3.数据库连接使用localhost(localhost要本地DNS解析,127.0.0.1无需解析,所以127.0.0.1会更快) 都不是本次问题所在! 过程:检查服务器SqlServer占用CPU90%以上,首先想到的是数据访问量大或者sql语句问题,但根据实际情况此原因排除。怀疑接口代码问题,但只要请求到达接口,里面逻辑处理很快返回。IIS问题?换了两台服务器不同IIS问题依旧。后来发现

  • 第四周课程总结&amp;试验报告(二)

    实验二Java简单类与对象 实验目的 掌握类的定义,熟悉属性、构造函数、方法的作用,掌握用类作为类型声明变量和方法返回值; 理解类和对象的区别,掌握构造函数的使用,熟悉通过对象名引用实例的方法和属性; 理解static修饰付对类、类成员变量及类方法的影响。 实验内容 1.写一个名为Rectangle的类表示矩形。其属性包括宽width、高height和颜色color,width和height都是double型的,而color则是String类型的。要求该类具有: (1)使用构造函数完成各属性的初始赋值 (2)使用get…()和set…()的形式完成属性的访问及修改 (3)提供计算面积的getArea()方法和计算周长的getLength()方法 2.银行的账户记录Account有账户的唯一性标识(11个长度的字符和数字的组合),用户的姓名,开户日期,账户密码(六位的数字,可以用0开头),当前的余额。银行规定新开一个账户时,银行方面提供一个标识符、账户初始密码123456,客户提供姓名,开户时客户可以直接存入一笔初始账户金额,不提供时初始余额为0。定义该类,并要求该类提供如下方法:存

相关推荐

推荐阅读