关于java:基于Java设计的小学数学辅助教学软件

拜访【WRITE-BUG数字空间】_[内附残缺源码和文档]课程设计目标本课程设计是利用 Java 进行程序设计的一个要害实际环节。它是依据教学计划的要求,在老师的领导下,对学生施行程序设计训练的必要过程,是对后期课堂教学成果的测验。其指标在于造就学生综合使用面向对象的办法实现小型软件系统的剖析与设计,纯熟应用 Java 语言及 JavaSE 类库实现桌面应用软件的开发和调试。通过这个课程设计,要求学生可能遵循软件开发过程的根本标准,依照课程设计的题目要求,独立地实现设计、编写、调试和测试应用程序及编写文档的工作。课程设计工作测试小学低年级学生的两位数的加减法的计算能力。需要剖析实现输出,依据输出抉择测试或者练习,再抉择一位数的加法或者减法,或两位数的加法或者减法,或混合运算。随机生成运算题目:依据之前输出的抉择,利用随机数的生成,生成相应的题目,并输入在屏幕上。生成标准答案库:依据之前生成的题目,通过计算机的运算将标准答案生成,并放入数组中。让用户输出运算的答案,并判断答案的对错,并记录答对了几题,在测试的环境下,只有当所有题目都答完之后才输入最终问题;在练习的环境下,每答完一题就输入是否答对,当答完所有题目的时候输入总成绩。零碎设计程序运行后首先是进入答题环境的抉择,能够抉择“测试”或者“练习”,抉择完之后进入第二个界面,第二个界面中能够抉择“一位数的加法”或者“一位数的减法”或者“两位数的加法”或者“两位数的减法”或者“混合运算”,抉择完之后,屏幕上会输入第一题的题目,若是在测试环境下,须要在用户输出一个答案后输入第二题,顺次直到第十题做完后,输入总成绩;若是在练习环境下,用户输出一个答案后会显示输出的答案是否正确,而后再显示第二题的题目,顺次直到第十题实现后,输入总成绩。零碎实现抉择界面是通过输出数据与程序中的数据进行比拟而后运行相应的函数实现的;在循环体构造下:题目的生成通过应用随机数的生成来生成的;依据生成的题目,通过计算机的运算生成标准答案,寄存于一个数组中;通过判断用户输出的答案是否与标准答案雷同,雷同的计数器加一,不同的计数器不变;最初的问题是通过对计数器的运算而造成的。总结这是我第一次接触 Java 这个程序语言,在周围的工夫外面我不仅要学习它,还要实现课程设计的代码编写,我想这对于本人当前的学习和工作都会有很大的帮忙。在这次设计中遇到了很多实际性的问题,在理论设计中才发现,书本上理论性的货色与在理论使用中的还是有肯定的出入的,所以有些问题岂但要深刻地了解,而且要一直地更正以前的谬误思维。所有问题必须要靠本人一点一滴的解决,而在解决的过程当中你会发现自己的能力在飞速的晋升。对于小学数学辅助教学软件,其程序是比较简单的,次要是解决程序设计中的问题,而程序设计是一个很灵便的货色,它反映了你解决问题的逻辑思维和创新能力,它才是一个设计的灵魂所在。因而在整个设计过程中大部分工夫是用在程序下面的。很多子程序是能够借鉴书本上的,但怎么连接各个子程序才是要害的问题所在,这须要对系统的构造很相熟。通过这次课程设计我也发现了本身存在的不足之处,尽管感觉实践上曾经把握,但在使用到实际的过程中仍有意想不到的困惑,通过一番致力才得以解决。这也激发了我今后努力学习的趣味,我想这将对我当前的学习产生踊跃的影响。在课程设计的过程中,当碰到不明确的问题时,指导老师总是急躁的解说,给我的设计以极大的帮忙,使我获益匪浅。因而非常感谢老师的教诲。通过这次设计,我懂得了学习的重要性,理解到理论知识与实际相结合的重要意义,学会了保持、急躁和致力,这将为本人今后的学习和工作做出了最好的楷模。我感觉作为一名软件工程业余的学生,这次课程设计是很有意义的。更重要的是如何把本人平时所学的货色利用到理论中。尽管本人对于这门课的内容理解的并不多,很多根底的货色都还没有很好的把握,然而在这四个星期的工夫里,通过自学和以前 c 语言的根底,对这门课有了肯定水平的理解。

April 18, 2023 · 1 min · jiezi

关于java:JDK8到JDK17有哪些吸引人的新特性

作者:京东批发 刘一达 前言2006年之后SUN公司决定将JDK进行开源,从此成立了OpenJDK组织进行JDK代码治理。任何人都能够获取该源码,并通过源码构建一个发行版公布到网络上。然而须要一个组织审核来确保构建的发行版是无效的, 这个组织就是JCP(Java Community Process)。2009年,SUN公司被Oracle公司"白嫖"(参考2018年Google赔款),此时大家应用的JDK通常都是Oracle公司的OpenJDK构建版本-OracleJDK。然而,Oracle公司是一个显著只讲商业而不论情怀的公司,接手Java商标之后,显著放慢了JDK的公布版本。2018年9月25日,JDK11胜利公布,这是一个LTS版本,蕴含了17个JEP的更新。与此同时,Oracle把JDK11起以往的商业个性全副开源给OpenJDK(例如:ZGC和Flight Recorder)。依据Oracle的官网说法(Oracle JDK Releases for Java 11 and Later),从JDK11之后,OracleJDK与OpenJDK的性能基本一致。而后,Oracle发表当前将会同时发行两款JDK:1. 一个是以GPLv2+CE协定下,由Oracle发行OpenJDK(简称为Oracle OpenJDK);2. 另一个是在OTN协定下的传统OracleJDK。这两个JDK共享绝大多数源码,外围差别在于前者能够收费在开发、测试和生产环境下应用,然而只有半年工夫的更新反对。后者各个人能够收费应用,然而生产环境中商用就必须付费,能够有三年工夫的更新反对。 2021年9月14日,Oracle JDK17公布,目前也是最新的Java LTS版本。有意思的是,Oracle居然"朝令夕改",OracleJDK17居然是收费的开源协定,并撑持长达8年的保护打算。目前公司外部应用的OracleJDK8最高版本为1.8.0.192,而Oracle在JDK8上开源协定反对的最高收费版本为jdk1.8.0_202。2022年Spring6和SpringBoot3相继推出,而反对的最低版本为JDK17。综上所述,JDK8为目前绝大多数以稳定性为主的零碎第一抉择,然而降级到高版本JDK也只是工夫问题。上面图表展现了JDk8到JDK17的每个版本升级的JEP个数。 通过以上图表,咱们能够得出结论,JDK8到JDK17蕴含大量新个性,为Oracle在Java近5年来的智慧结晶。目前市面上的公司还是只有多数零碎会抉择JDK11或者JDK17作为线上技术选型,如果抉择从JDK8降级到JDK17必然会有十分大的挑战和较多须要填的坑。本文次要介绍JDK8到JDk17近200个JEP中比拟有价值的新个性(依照价值从高到低排序),这里有一部分个性作者也在线上环境应用过,也会将其中的应用心得分享给大家。 外围JEP性能及原理介绍一、Java平台模块化零碎(Jigsaw我的项目)JDK9最夺目的新个性就是Java平台模块化零碎(JPMS,Java Platform Module System),通过Jigsaw我的项目施行。Jigsaw我的项目是Java倒退过程的一个微小里程碑,Java模块系统对Java零碎产生十分深远的影响。与JDK的函数式编程和 Lamda表达式存在实质不同 ,Java模块零碎是对整个Java生态系统做出的扭转。 同时也是JDK7到JDK9的第一跳票王我的项目。Jigsaw我的项目本打算于在2010年随同着JDK7公布,随着Sun公司的败落及Oracle公司的接手,Jigsaw我的项目从JDK7始终跳票到JDK9才公布。前后经验了前后将近10年的工夫。即便在2017JDK9公布前夕,Jigsaw我的项目还是差点胎死腹中。起因是以IBM和Redhat为首的13家企业在JCP委员会上一手否决了Jigsaw我的项目作为Java模块化标准进入JDK9公布范畴的布局。起因无非就是IBM心愿为本人的OSGI技术在Java模块化标准中争取一席之地。然而Oracle公司没有任何的让步,不惜向JCP发去公开信,宣称如果Jigsaw提案无奈通过,那么Oracle将间接本人开发带有Jigsaw我的项目的java新版本。经验了前后6次投票,最终JDK9还是带着Jigsaw我的项目最终公布了。然而,令人悲观的是,Java模块化标准中还是给Maven、Gradle和OSGI等我的项目保留了一席之地。对于用户来说,想要实现残缺模块化我的项目,必须应用多个技术相互合作,还是减少了复杂性。如果大家想要对模块化技术有更多深刻理解,举荐浏览书籍《Java9模块化开发:外围准则与实际》 1、什么是Java模块化?简略了解,Java模块化就是将目前多个包(package)组成一个封装体,这个封装体有它的逻辑含意 ,同时也存在具体实例。同时模块遵循以下三个外围准则: 强封装性:一个模块能够选择性的对其余模块暗藏局部实现细节。定义良好的接口:一个模块只有封装是不够的,还要通过对外裸露接口与其余模块交互。因而,裸露的接口必须有良好的定义。显示依赖:一个模块通常须要协同其余模块一起工作,该模块必须显示的依赖其余模块 ,这些依赖关系同时也是模块定义的一部分。2、为什么要做模块化?模块化是分而治之的一个重要实际机制,微服务、OSGI和DDD都能够看到模块化思维的影子。当初很多大型的Java我的项目都是通过maven或者gradle进行版本治理和我的项目构建,模块的概念在Maven和gradle中早就存在,两者的不同下文也会说到。当初让咱们一起回顾一下目前在应用JDK搭建简单我的项目时遇到的一些问题: 2.1 如何使得Java SE应用程序更加轻量级的部署?java包的实质只不过是类的限定名。jar包的实质就是将一组类组合到一起。一旦将多个Jar包放入ClassPath,最终失去只不过是一大堆文件而已。如何保护这么宏大的文件构造?目前最无效的形式,也是只能依赖mave或者gradle等我的项目构建工具。那最底层的Java平台的Jar包如何保护?如果我只是想部署一个简答的 helloworld利用,我须要一个JRE和一个用户编译的Jar包,并将这个Jar包放到classpath中去。JDK9以前,JRE的运行依赖咱们的外围java类库-rt.jar。rt.jar是一个开箱即用的全量java类库,要么不应用,要么应用全副。直到JDK8,rt.jar的大小为60M,随着JDK的继续倒退,这个包必然会越来越大。而且全量的java类库,给JRE也带来了额定的性能损耗。Java应用程序如果能选择性的加载rt.jar中的文件该多好? 2.2 在裸露的JAR包中,如何暗藏局部API和类型?在应用Dubbo等RPC框架中,provider须要提供调用的接口定义Jar包,在该Jar包中蕴含一个共该Jar包外部应用的常量聚合类Constannt,放在constant包内。如何能力裸露JAR包的同时,暗藏常量聚合类Constant? 2.3 始终蒙受NoClassDefFoundError的折磨通过什么形式,能够晓得一个Jar包依赖了哪些其余的 Jar包?JDK自身目前没有提供,能够通过Maven工具实现。那为什么不让Java平台本身就提供这些性能? 3、JPMS如何解决现有问题?JPMS具备两个重要的指标: 强封装(Strong encapsulation): 每一个模块都能够申明了哪些包是对外裸露的,java编译和运行时就能够施行这些规定来确保内部模块无奈应用外部类型。牢靠配置(Reliable configuration):每一模块都申明了哪些是它所需的,那么在运行时就能够查看它所需的所有模块在利用启动运行前是否都有。Java平台自身就是必须要进行模块化革新的简单我的项目,通过Jigsaw我的项目落地。 3.1 Project JigsawModular development starts with a modular platform. —Alan Bateman 2016.9模块化开始于模块化平台 。Project Jigsaw 有如下几个指标: 可伸缩平台(Scalable platform):逐步从一个宏大的运行时平台到有有能力放大到更小的计算机设备。安全性和可维护性(Security and maintainability):更好的组织了平台代码使得更好保护。暗藏外部API和更明确的接口定义晋升了平台的安全性。晋升应用程序性能(Improved application performance):只有必须的运行时runtimes的更小的平台能够带来更快的性能。更简略的开发体验Easier developer experience:模块零碎与模块平台的联合使得开发者更容易构建利用和库。对Java平台进行模块化革新是一个巨大工程,JDK9之前,rt.jar是个微小的Java运行时类库,大略有60MB左右。JDK9将其拆分成90个模块左右 ,如下图所示(图片起源《Java 9模块化开发》): ...

April 18, 2023 · 6 min · jiezi

关于java:基于SSM和Mysql实现的图书管理系统

拜访【WRITE-BUG数字空间】_[内附残缺源码和文档] 我的项目介绍通过一段时间对SSM整合的学习,对根本实践以及次要知识点的把握,实现繁难图书管理系统,当然必定有很多能够改良的中央。之前没有记录SSM整合的过程,这次刚好我的项目有更粗浅的了解。以前解决问题的过程和办法并没有及时记录,当前在本人的小我的项目中遇到我再整顿分享一下。这次,先说说三大框架整合过程。集体认为应用框架并不是很难,要害要了解其思维,这对于咱们进步编程程度很有帮忙。不过,如果用都不会,谈思维就变成夸夸其谈了!!!先技术,再思维。实际出真知。我的项目中相干的配置文件,大家能够拿来间接copy ,只须要改改外面的包名以及Mapper.xml配置即可应用。分为管理员、用户和图书模块。其中管理员实现了登录,对读者与图书的增删改查,还有治理读者的图书借阅、续借、偿还、预约和逾期解决。该我的项目已实现性能:管理员的登录与退出,登录谬误提醒图书的新增,批改,下架,彻底删除,从新上架,分页显示,依照图书题目与作者名字含糊查问还有其它未实现的性能可自由发挥,包含登录后的欢送页面可自由发挥该零碎执行过程无任何报错,如果呈现谬误请仔细检查配置软件架构MyEclipseSSM框架JSPMySQL8Tomcat8.5Maven应用阐明借阅:同一本书只可借阅一本,每次可借30天续借:同一本书只可续借一次,每次续借15天偿还:在偿还日期内方可偿还图书预约:当图书余量为0时,可预约该图书逾期解决:需缴费,分为缴费并还书和缴费未还书上架图书:须要输出图书根本信息和上架数量

April 18, 2023 · 1 min · jiezi

关于java:HDFS基础知识上

HDFS基础知识(上)大家好,好久不见,我是大圣,明天更新一篇 HDFS 基础知识的文章。话不多说,间接上纲要 简略说一下最近的安顿,我会出一个 HDFS 系列的文章,让大家从理解 HDFS 根底开始,始终到相熟 HDFS 外围源码。文章的次要系列包含以下几个局部: 1 .HDFS 基础知识 2 . HDFS 源码图解 那接下来,咱们开始明天的内容。 1.HDFS 架构演变1.1 hadoop 简介Hadoop 到目前为止倒退曾经有 10 余年,版本经验了无数次的更新迭代,目前业内大家把 Hadoop 大的版本分为 Hadoop1,Hadoop2,Hadoop3 三个版本。 hadoop1 版本刚进去的时候是为了解决两个问题:一个是海量数据如何存储的问题,一个是海量数据如何计算的问题。Hadoop1 的外围设计就是 HDFS 和 MapReduce。HDFS 解决了海量数据如何存储的问题,MapReduce 解决了海量数据如何计算的问题。 HDFS 的全称:Hadoop Distributed File System 1.2 HDFS 的重要性大数据中最重要的两个货色就是存储和计算,在存储方面当初大部分的公司都采纳 HDFS 作为底层的数据存储。如果公司大数据存储经常出现问题,那么就可能导致数据不可用,或者数据失落,这在生产环境是齐全不容许的。 比方还有数据小文件问题,数据文件过大导致查问速度过慢等问题,如果这些问题常常存在,那么会导致咱们的数据平台是不可用的。所以我认为公司的大数据存储是大数据中比拟根底而且最重要的一环。 所以对 HDFS 还是很值得深入研究的,一方面它作为大数据的底层存储的重要性显而易见,另一方面对 HDFS 理解比拟深刻,它待遇是真的好呀,如下图: 1.3 HDFS 的架构演进之路 HDFS 是 Hadoop 外面的一个组件,下面说过 Hadoop 通过了 hadoop1,Hadoop2,Hadoop3 三个大的版本迭代,所以 HDFS 也经验了 HDFS1,HDFS2,HDFS3 三个版本的迭代。 ...

April 17, 2023 · 3 min · jiezi

关于java:HDFS基础知识上

HDFS基础知识(上)大家好,好久不见,我是大圣,明天更新一篇 HDFS 基础知识的文章。话不多说,间接上纲要 简略说一下最近的安顿,我会出一个 HDFS 系列的文章,让大家从理解 HDFS 根底开始,始终到相熟 HDFS 外围源码。文章的次要系列包含以下几个局部: 1 .HDFS 基础知识 2 . HDFS 源码图解 那接下来,咱们开始明天的内容。 1.HDFS 架构演变1.1 hadoop 简介Hadoop 到目前为止倒退曾经有 10 余年,版本经验了无数次的更新迭代,目前业内大家把 Hadoop 大的版本分为 Hadoop1,Hadoop2,Hadoop3 三个版本。 hadoop1 版本刚进去的时候是为了解决两个问题:一个是海量数据如何存储的问题,一个是海量数据如何计算的问题。Hadoop1 的外围设计就是 HDFS 和 MapReduce。HDFS 解决了海量数据如何存储的问题,MapReduce 解决了海量数据如何计算的问题。 HDFS 的全称:Hadoop Distributed File System 1.2 HDFS 的重要性大数据中最重要的两个货色就是存储和计算,在存储方面当初大部分的公司都采纳 HDFS 作为底层的数据存储。如果公司大数据存储经常出现问题,那么就可能导致数据不可用,或者数据失落,这在生产环境是齐全不容许的。 比方还有数据小文件问题,数据文件过大导致查问速度过慢等问题,如果这些问题常常存在,那么会导致咱们的数据平台是不可用的。所以我认为公司的大数据存储是大数据中比拟根底而且最重要的一环。 所以对 HDFS 还是很值得深入研究的,一方面它作为大数据的底层存储的重要性显而易见,另一方面对 HDFS 理解比拟深刻,它待遇是真的好呀,如下图: 1.3 HDFS 的架构演进之路 HDFS 是 Hadoop 外面的一个组件,下面说过 Hadoop 通过了 hadoop1,Hadoop2,Hadoop3 三个大的版本迭代,所以 HDFS 也经验了 HDFS1,HDFS2,HDFS3 三个版本的迭代。 ...

April 17, 2023 · 3 min · jiezi

关于java:Spring-Boot-接口加解密新姿势来了

1. 介绍在咱们日常的Java开发中,免不了和其余零碎的业务交互,或者微服务之间的接口调用 如果咱们想保障数据传输的平安,对接口出加入密,入参解密。 然而不想写反复代码,咱们能够提供一个通用starter,提供通用加密解密性能 2. 前置常识2.1 hutool-crypto加密解密工具 hutool-crypto提供了很多加密解密工具,包含对称加密,非对称加密,摘要加密等等,这不做具体介绍。 2.2 request流只能读取一次的问题 2.2.1 问题:在接口调用链中,request的申请流只能调用一次,解决之后,如果之后还须要用到申请流获取数据,就会发现数据为空。 比方应用了filter或者aop在接口解决之前,获取了request中的数据,对参数进行了校验,那么之后就不能在获取request申请流了 2.2.2 解决办法继承HttpServletRequestWrapper,将申请中的流copy一份,复写getInputStream和getReader办法供内部应用。每次调用后的getInputStream办法都是从复制进去的二进制数组中进行获取,这个二进制数组在对象存在期间统一存在。 应用Filter过滤器,在一开始,替换request为本人定义的能够屡次读取流的request。 这样就实现了流的反复获取 InputStreamHttpServletRequestWrapperpackage xyz.hlh.cryptotest.utils;import org.apache.commons.io.IOUtils;import javax.servlet.ReadListener;import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStreamReader;/** * 申请流反对屡次获取 */public class InputStreamHttpServletRequestWrapper extends HttpServletRequestWrapper { /** * 用于缓存输出流 */ private ByteArrayOutputStream cachedBytes; public InputStreamHttpServletRequestWrapper(HttpServletRequest request) { super(request); } @Override public ServletInputStream getInputStream() throws IOException { if (cachedBytes == null) { // 首次获取流时,将流放入 缓存输出流 中 cacheInputStream(); } // 从 缓存输出流 中获取流并返回 return new CachedServletInputStream(cachedBytes.toByteArray()); } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } /** * 首次获取流时,将流放入 缓存输出流 中 */ private void cacheInputStream() throws IOException { // 缓存输出流以便屡次读取。为了不便, 我应用 org.apache.commons IOUtils cachedBytes = new ByteArrayOutputStream(); IOUtils.copy(super.getInputStream(), cachedBytes); } /** * 读取缓存的申请注释的输出流 * <p> * 用于依据 缓存输出流 创立一个可返回的 */ public static class CachedServletInputStream extends ServletInputStream { private final ByteArrayInputStream input; public CachedServletInputStream(byte[] buf) { // 从缓存的申请注释创立一个新的输出流 input = new ByteArrayInputStream(buf); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener listener) { } @Override public int read() throws IOException { return input.read(); } }}HttpServletRequestInputStreamFilterpackage xyz.hlh.cryptotest.filter;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import xyz.hlh.cryptotest.utils.InputStreamHttpServletRequestWrapper;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import java.io.IOException;import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;/** * @author HLH * @description: * 申请流转换为屡次读取的申请流 过滤器 * @email 17703595860@163.com * @date : Created in 2022/2/4 9:58 */@Component@Order(HIGHEST_PRECEDENCE + 1) // 优先级最高public class HttpServletRequestInputStreamFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 转换为能够屡次获取流的request HttpServletRequest httpServletRequest = (HttpServletRequest) request; InputStreamHttpServletRequestWrapper inputStreamHttpServletRequestWrapper = new InputStreamHttpServletRequestWrapper(httpServletRequest); // 放行 chain.doFilter(inputStreamHttpServletRequestWrapper, response); }}2.3 SpringBoot的参数校验validation ...

April 17, 2023 · 7 min · jiezi

关于java:Java并发工具合集JUC大爆发

并发工具类通常咱们所说的并发包也就是java.util.concurrent(JUC),集中了Java并发的各种工具类, 正当地应用它们能帮忙咱们疾速地实现性能 。作者: 博学谷狂野架构师GitHub:GitHub地址 (有我精心筹备的130本电子书PDF) 只分享干货、不吹水,让咱们一起加油!1. CountDownLatchCountDownLatch是一个同步计数器,初始化的时候 传入须要计数的线程期待数,能够是须要期待执行实现的线程数,或者大于 ,个别称为发令枪。\ countdownlatch 是一个同步类工具,不波及锁定,当count的值为零时以后线程持续运行,不波及同步,只波及线程通信的时候,应用它较为适合 1.1 作用用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用),是一组线程期待其余的线程实现工作当前在执行,相当于加强版join。留神:这是一个一次性操作 - 计数无奈重置。 如果你须要一个重置的版本计数,思考应用CyclicBarrier。 1.2 举例 咱们去组团玩耍一样,总共30集体,来的人要期待还没有到的人,始终等到第30集体到了,咱们才开始登程,在期待过程中,其他人(线程)是期待状态不做任何事件的,始终等所有人(线程)到齐了(筹备实现)才开始执行。 1.3 概念countDownLatch这个类使一个线程期待其余线程各自执行结束后再执行。是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行结束后,计数器的值就-1,当计数器的值为0时,示意所有线程都执行结束,而后在闭锁上期待的线程就能够复原工作了。咱们关上CountDownLatch的源代码剖析,咱们发现最重要的办法就是一下这两个办法: //阻塞以后线程,期待其余线程执行实现,直到计数器计数值减到0。public void await() throws InterruptedException;//阻塞以后线程指定的工夫,如果达到工夫就放行,期待其余线程执行实现,直到计数器计数值减到0。public boolean await(long timeout, TimeUnit unit) throws InterruptedException//负责计数器的减一。public void countDown():1.4 利用场景1.4.1 多线程压测有时咱们想同时启动多个线程,实现最大水平的并行性。 例如,咱们想测试一个单例类。如果咱们创立一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上期待,那么咱们能够很轻松地实现测试。咱们只需调用 一次countDown()办法就能够让所有的期待线程同时复原执行。 1.4.2 期待其余线程 例如应用程序启动类要确保在解决用户申请前,所有N个内部零碎曾经启动和运行了,例如解决excel中多个表单,如果一个一个进去很耗IO和性能,咱们能够等100或者1000个线程都实现了表单的操作后一下子写进excel表单中。 留神:一个线程不肯定只能做countDown一次,也能够countDown屡次 1.5 示例1.5.1 筹备实现后执行在理论我的项目中可能有些线程须要资源筹备实现后能力进行执行,这个时候就能够应用countDownLatchpackage chapter02.countdownlatch;import java.util.Random;import java.util.concurrent.*;/** * countdownlatch 示例 */public class CountDownLatchTest { private static ExecutorService executorService = Executors.newFixedThreadPool(10); private static Random random = new Random(); public static void execute(CountDownLatch countDownLatch) { //获取一个随机数 long sleepTime = random.nextInt(10); //获取线程ID long threadId = Thread.currentThread().getId(); System.out.println("线程ID" + threadId + ",开始执行--countDown"); try { //睡眠随机秒 Thread.sleep(sleepTime * 1000); } catch (InterruptedException e) { e.printStackTrace(); } //计数器减1 countDownLatch.countDown(); System.out.println("线程ID" + threadId + ",筹备工作实现耗时:" + sleepTime + "以后工夫" + System.currentTimeMillis()); try { //线程期待其余工作实现后唤醒 countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程ID" + threadId + ",开始执行工作,以后工夫:" + System.currentTimeMillis()); } public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(5); for (int i = 0; i < 5; i++) { executorService.submit(() -> { execute(countDownLatch); }); } //线程期待其余工作实现后唤醒 countDownLatch.await(); Thread.sleep(1000); executorService.shutdown(); System.out.println("全副工作执行实现"); }}1.5.2 多线程压测在实战我的项目中,咱们除了应用 jemter 等工具进行压测外,还能够本人入手应用 CountDownLatch 类编写压测代码。 能够说 jemter 的并发压测背地也是应用的 CountDownLatch,可见把握 CountDownLatch 类的应用是有如许的重要, CountDownLatch是Java多线程同步器的四大金刚之一,CountDownLatch可能使一个线程期待其余线程实现各自的工作后再执行。 ...

April 17, 2023 · 6 min · jiezi

关于java:SpringBoot2X整合Lucene7X实现轻量级搜索引擎

基础知识解析: 索引(Index):在Lucene中,索引是一个蕴含文档(Document)的数据结构,相似于MySQL中的表。Lucene将文档中的字段进行索引,以便后续进行高效的搜寻。每个索引蕴含多个文档,而每个文档能够蕴含多个字段。文档(Document):在Lucene中,文档是要进行索引和搜寻的根本单位,相似于MySQL中的一行数据。文档能够蕴含多个字段,每个字段都能够蕴含一个或多个值。文档能够是一个蕴含文本数据的Java对象,例如一篇文章或一条记录。字段(Field):在Lucene中,字段是文档中的一个属性或值,相似于MySQL中的列。字段能够蕴含不同类型的值,例如文本、数字、日期等。每个字段都能够被索引和搜寻。在创立索引时需指定类型的参数:IndexWriterConfig.OpenMode.CREATE: 如果索引目录中不存在索引,则创立一个新的索引;如果索引目录中曾经存在索引,则删除现有的索引并创立一个新的索引。这个模式会齐全清空现有的索引,而后从头开始构建新的索引。IndexWriterConfig.OpenMode.APPEND: 如果索引目录中不存在索引,则创立一个新的索引;如果索引目录中曾经存在索引,则在现有的索引上追加新的索引。这个模式会在现有的索引根底上增量地增加新的文档和更新已有的文档,而不会清空现有的索引。IndexWriterConfig.OpenMode.CREATE_OR_APPEND: 如果索引目录中不存在索引,则创立一个新的索引;如果索引目录中曾经存在索引,则在现有的索引上追加新的索引。这个模式会依据索引目录中是否存在索引来决定是创立新的索引还是在现有的索引上追加创立字段时需指定的类型:StringField:用于存储不须要进行分词的文本数据,实用于关键字、标识符等须要准确匹配的状况。TextField:用于存储须要进行分词的文本数据,实用于文章内容、形容等须要进行全文搜寻的状况。SortedDocValuesField:用于存储须要进行排序的文本数据,实用于日期、价格等须要进行范畴查问或排序的状况。BinaryDocValuesField:用于存储二进制数据,例如图片、音频等。NumericDocValuesField:用于存储数值型数据,例如整数、浮点数等,实用于数值范畴查问或排序的状况。IntPoint、FloatPoint、LongPoint、DoublePoint:别离用于存储整数、浮点数、长整数、双精度浮点数类型的数据,用于进行数值范畴查问。StringField、TextField(带排序):这些字段类型在 StringField 和 TextField 的根底上增加了排序功能,实用于须要进行排序的文本数据。SortedNumericDocValuesField:用于存储多值数值型数据,例如多个数值型数据组成的数组或汇合。SortedSetDocValuesField:用于存储多值文本数据,例如多个字符串组成的汇合。LatLonPoint:用于存储地理位置信息,包含经度和纬度,用于进行地理位置范畴查问。DatePoint:用于存储日期信息,包含年、月、日,用于进行日期范畴查问。BinaryPoint:用于存储二进制数据,例如 IPv4 地址、UUID 等。StringField、TextField(带向量):这些字段类型在 StringField 和 TextField 的根底上增加了向量存储性能,用于进行文本向量检索。以下为集成例子:POM文件导入相干依赖包: 我的项目springboot是2.2.2版本 <!-- lucene外围库 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>7.6.0</version> </dependency> <!-- Lucene的查问解析器 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-queryparser</artifactId> <version>7.6.0</version> </dependency> <!-- lucene的默认分词器库 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-common</artifactId> <version>7.6.0</version> </dependency> <!-- lucene的高亮显示 --> <dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-highlighter</artifactId> <version>7.6.0</version> </dependency> <!-- ik分词器 --> <dependency> <groupId>com.janeluo</groupId> <artifactId>ikanalyzer</artifactId> <version>2012_u6</version> </dependency>若呈现以下问题,有可能jar包版本不兼容问题,需自行从新实现分词器 org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.AbstractMethodError: org.apache.lucene.analysis.Analyzer.createComponents(Ljava/lang/String;)Lorg/apache/lucene/analysis/Analyzer$TokenStreamComponents;如下: import org.apache.lucene.analysis.Analyzer;import org.apache.lucene.analysis.Tokenizer;public class MyIKAnalyzer extends Analyzer { private boolean useSmart; public boolean useSmart() { return this.useSmart; } public void setUseSmart(boolean useSmart) { this.useSmart = useSmart; } public MyIKAnalyzer() { this(false); } @Override protected TokenStreamComponents createComponents(String s) { Tokenizer _MyIKTokenizer = new MyIKTokenizer(this.useSmart()); return new TokenStreamComponents(_MyIKTokenizer); } public MyIKAnalyzer(boolean useSmart) { this.useSmart = useSmart; }}import org.apache.lucene.analysis.Tokenizer;import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;import org.apache.lucene.analysis.tokenattributes.TypeAttribute;import org.wltea.analyzer.core.IKSegmenter;import org.wltea.analyzer.core.Lexeme;import java.io.IOException;public class MyIKTokenizer extends Tokenizer { private IKSegmenter _IKImplement; private final CharTermAttribute termAtt = (CharTermAttribute)this.addAttribute(CharTermAttribute.class); private final OffsetAttribute offsetAtt = (OffsetAttribute)this.addAttribute(OffsetAttribute.class); private final TypeAttribute typeAtt = (TypeAttribute)this.addAttribute(TypeAttribute.class); private int endPosition; //useSmart:设置是否应用智能分词。默认为false,应用细粒度分词,这里如果更改为TRUE,那么搜寻到的后果可能就少的很多 public MyIKTokenizer(boolean useSmart) { this._IKImplement = new IKSegmenter(this.input, useSmart); } public final boolean incrementToken() throws IOException { this.clearAttributes(); Lexeme nextLexeme = this._IKImplement.next(); if (nextLexeme != null) { this.termAtt.append(nextLexeme.getLexemeText()); this.termAtt.setLength(nextLexeme.getLength()); this.offsetAtt.setOffset(nextLexeme.getBeginPosition(), nextLexeme.getEndPosition()); this.endPosition = nextLexeme.getEndPosition(); this.typeAtt.setType(nextLexeme.getLexemeTypeString()); return true; } else { return false; } } public void reset() throws IOException { super.reset(); this._IKImplement.reset(this.input); } public final void end() { int finalOffset = this.correctOffset(this.endPosition); this.offsetAtt.setOffset(finalOffset, finalOffset); }}实体类对象: ...

April 17, 2023 · 6 min · jiezi

关于java:安装Zookeeper和Kafka集群

装置Zookeeper和Kafka集群本文介绍如何装置Zookeeper和Kafka集群。为了不便,介绍的是在一台服务器上的装置,理论应该装置在多台服务器上,但步骤是一样的。 装置Zookeeper集群下载安装包从官网上下载安装包: curl https://dlcdn.apache.org/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1-bin.tar.gz -o apache-zookeeper-3.7.1-bin.tar.gz解压: tar xvf apache-zookeeper-3.7.1-bin.tar.gz 配置创立目录 zk1,而后增加如下配置: zk1/myid: 1zk1/zk.config: tickTime=2000initLimit=10syncLimit=5dataDir=/Users/larry/IdeaProjects/pkslow-samples/other/install-kafka-cluster/src/main/zookeeper/zk1clientPort=2181server.1=127.0.0.1:2888:3888server.2=127.0.0.1:2889:3889server.3=127.0.0.1:2890:3890对于zk2和zk3也反复同样的步骤,并批改相应的配置: zk2/myid: 2zk2/zk.config: tickTime=2000initLimit=10syncLimit=5dataDir=/Users/larry/IdeaProjects/pkslow-samples/other/install-kafka-cluster/src/main/zookeeper/zk2clientPort=2182server.1=127.0.0.1:2888:3888server.2=127.0.0.1:2889:3889server.3=127.0.0.1:2890:3890zk3/myid: 3zk3/zk.config: tickTime=2000initLimit=10syncLimit=5dataDir=/Users/larry/IdeaProjects/pkslow-samples/other/install-kafka-cluster/src/main/zookeeper/zk3clientPort=2183server.1=127.0.0.1:2888:3888server.2=127.0.0.1:2889:3889server.3=127.0.0.1:2890:3890启动集群启动三个服务如下: $ ./apache-zookeeper-3.7.1-bin/bin/zkServer.sh start ./zk1/zk.config ZooKeeper JMX enabled by defaultUsing config: ./zk1/zk.configStarting zookeeper ... STARTED$ ./apache-zookeeper-3.7.1-bin/bin/zkServer.sh start ./zk2/zk.config ZooKeeper JMX enabled by defaultUsing config: ./zk2/zk.configStarting zookeeper ... STARTED$ ./apache-zookeeper-3.7.1-bin/bin/zkServer.sh start ./zk3/zk.config ZooKeeper JMX enabled by defaultUsing config: ./zk3/zk.configStarting zookeeper ... STARTED查看状态通过status命令查看: $ ./apache-zookeeper-3.7.1-bin/bin/zkServer.sh status ./zk1/zk.config ZooKeeper JMX enabled by defaultUsing config: ./zk1/zk.configClient port found: 2181. Client address: localhost. Client SSL: false.Mode: follower$ ./apache-zookeeper-3.7.1-bin/bin/zkServer.sh status ./zk2/zk.config ZooKeeper JMX enabled by defaultUsing config: ./zk2/zk.configClient port found: 2182. Client address: localhost. Client SSL: false.Mode: leader$ ./apache-zookeeper-3.7.1-bin/bin/zkServer.sh status ./zk3/zk.config ZooKeeper JMX enabled by defaultUsing config: ./zk3/zk.configClient port found: 2183. Client address: localhost. Client SSL: false.Mode: follower连贯其中一个服务并增加数据: ...

April 17, 2023 · 2 min · jiezi

关于java:公司入职一个阿里大佬把-Spring-Boot-系统启动时间从-7-分钟降到了-40-秒

作者:Debugger \链接:https://juejin.cn/post/7181342523728592955 0 背景公司 SpringBoot 我的项目在日常开发过程中发现服务启动过程异样迟缓,经常须要6-7分钟能力裸露端口,重大升高开发效率。通过 SpringBoot 的 SpringApplicationRunListener 、BeanPostProcessor 原理和源码调试等伎俩排查发现,在 Bean 扫描和 Bean 注入这个两个阶段有很大的性能瓶颈。 通过 JavaConfig 注册 Bean, 缩小 SpringBoot 的扫描门路,同时基于 Springboot 主动配置原理对第三方依赖优化革新,将服务本地启动工夫从7min 降至40s 左右的过程。 本文会波及以下知识点: 基于 SpringApplicationRunListener 原理察看 SpringBoot 启动 run 办法;基于 BeanPostProcessor 原理监控 Bean 注入耗时;SpringBoot Cache 自动化配置原理;SpringBoot 自动化配置原理及 starter 革新;1 耗时问题排查SpringBoot 服务启动耗时排查,目前有2个思路: 排查 SpringBoot 服务的启动过程;排查 Bean 的初始化耗时;Spring Boot 根底就不介绍了,举荐看这个收费教程: https://github.com/javastacks/spring-boot-best-practice1.1 察看 SpringBoot 启动 run 办法该我的项目应用基于 SpringBoot 革新的外部微服务组件 XxBoot 作为服务端实现,其启动流程与 SpringBoot 相似,分为 ApplicationContext 结构和 ApplicationContext 启动两局部,即通过构造函数实例化 ApplicationContext 对象,并调用其 run 办法启动服务: ...

April 17, 2023 · 5 min · jiezi

关于java:Spring-cloud-Gateway-换成-Apache-APISIX-云原生-API-网关初体验

https://landscape.cncf.io/card-mode?category=api-gateway&grou... 一、环境我的项目筹备1、创立Spring Cloud Gateway API 网关我的项目新建 demo-gateway 我的项目pom 依赖如下 <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demo-gateway</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo-gateway</name> <description>demo-gateway</description> <properties> <java.version>17</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.6.13</spring-boot.version> <spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version> <spring-cloud.version>2021.0.5</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>17</source> <target>17</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <configuration> <mainClass>com.example.gateway.DemoGatewayApplication</mainClass> <skip>true</skip> </configuration> <executions> <execution> <id>repackage</id> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build></project>配置文件 bootstrap.yml ...

April 17, 2023 · 2 min · jiezi

关于java:SimpleDateFormat时间格式化不同模型性能对比

SimpleDateFormat三种不同的应用办法 这里总结一下SimpleDateFormat的三种用法不同的性能比照后果。 尽管SimpleDateFormat性能最差,线程不平安,然而一些老旧的零碎还是有那么多的人用,这里就简略比照一下性能差别代码public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.S"); @ApiOperation("SimpleDateFormat-获取以后工夫戳") @ApiResponses({ @ApiResponse(code = 200, message = "OK", response= R.class), }) @RequestMapping(value = "/SimpleDateFormat", method = RequestMethod.GET) public String SimpleDateFormatCase(){ long startTime = System.currentTimeMillis(); SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.S"); String date = sdf1.format(System.currentTimeMillis()); log.info("解析工夫耗时:" + (System.currentTimeMillis() - startTime) + "ms"); return date; } @ApiOperation("SimpleDateFormat-获取以后工夫戳2-复用SimpleDateFormat") @ApiResponses({ @ApiResponse(code = 200, message = "OK", response= R.class), }) @RequestMapping(value = "/SimpleDateFormat2", method = RequestMethod.GET) public String SimpleDateFormatCase2(){ long startTime = System.currentTimeMillis(); String date = sdf.format(System.currentTimeMillis()); log.info("解析工夫耗时:" + (System.currentTimeMillis() - startTime) + "ms"); return date; } @ApiOperation("SimpleDateFormat-获取以后工夫戳3-应用线程锁") @ApiResponses({ @ApiResponse(code = 200, message = "OK", response= R.class), }) @RequestMapping(value = "/SimpleDateFormat3", method = RequestMethod.GET) public String SimpleDateFormatCase3(){ String date = DateFormatUtil.formatDateTime(new Date()); return date; }压测形式 间接用jmeter发压,10并发,发压100s,服务器监控用sar命令简略监控(也不是什么很简单的业务,第三方监控组件没必要) ...

April 17, 2023 · 1 min · jiezi

关于java:Java中Future接口详解

主打一手后果导向;一、背景在零碎中,异步执行工作,是很常见的性能逻辑,然而在不同的场景中,又存在很多细节差别; 有的工作只强调「执行过程」,并不需要追溯工作本身的「执行后果」,这里并不是指对系统和业务产生的成果,比方定时工作、音讯队列等场景; 然而有些工作即强调「执行过程」,又须要追溯工作本身的「执行后果」,在流程中依赖某个异步后果,判断流程是否中断,比方「并行」解决; 【串行解决】整个流程依照逻辑逐步推进,如果出现异常会导致流程中断; 【并行处理】主流程依照逻辑逐步推进,其余「异步」交互的流程执行结束后,将后果返回到主流程,如果「异步」流程异样,会影响局部后果; 此前在《「订单」业务》的内容中,聊过对于「串行」和「并行」的利用比照,即在订单详情的加载过程中,通过「并行」的形式读取:商品、商户、订单、用户等信息,晋升接口的响应工夫; 二、Future接口1、入门案例异步是对流程的解耦,然而有的流程中又依赖异步执行的最终后果,此时就能够应用「Future」接口来达到该目标,先来看一个简略的入门案例; public class ServerTask implements Callable<Integer> { @Override public Integer call() throws Exception { Thread.sleep(2000); return 3; }}public class FutureBase01 { public static void main(String[] args) throws Exception { TimeInterval timer = DateUtil.timer(); // 线程池 ExecutorService executor = Executors.newFixedThreadPool(3); // 批量工作 List<ServerTask> serverTasks = new ArrayList<>() ; for (int i=0;i<3;i++){ serverTasks.add(new ServerTask()); } List<Future<Integer>> taskResList = executor.invokeAll(serverTasks) ; // 后果输入 for (Future<Integer> intFuture:taskResList){ System.out.println(intFuture.get()); } // 耗时统计 System.out.println("timer...interval = "+timer.interval()); }}这里模仿一个场景,以线程池批量执行异步工作,在工作内线程休眠2秒,以并行的形式最终获取全副后果,只耗时2秒多一点,如果串行的话耗时必定超过6秒; ...

April 17, 2023 · 5 min · jiezi

关于java:深入理解-Java-的整型类型如何实现-225

在开始对于 Java 的整型类型探讨之前,让咱们先看下这段神奇的Java代码: public static void main(String[] args) throws Exception { doSomethingMagic(); System.out.printf("2 + 2 = %d", 2 + 2);}执行后果,控制台打印的内容:2 + 2 = 5 那么 doSomethingMagic 办法到底做了什么神奇的事件呢? private static void doSomethingMagic() throws Exception { Class cache = Integer.class.getDeclaredClasses()[0]; Field c = cache.getDeclaredField("cache"); c.setAccessible(true); Integer[] array = (Integer[]) c.get(cache); array[132] = array[133];}所以这个例子其实蕴含了 Java 中整型类型 Integer 的一个知识点。 可能有的敌人对于 doSomethingMagic 外面的代码有点摸不着头脑,让咱们先查看上图第17行 2 + 2 反编译进去的代码: 编译器将 2 + 2 的值先计算出来,等于 4. ...

April 16, 2023 · 2 min · jiezi

关于java:Java房屋出租系统

房屋出租零碎-需要实现基于文本界面的《房屋出租软件》。可能实现对房屋信息的增加、批改和删除(用数组实现),并可能打印屋宇明细表 房屋出租零碎-界面我的项目界面- 主菜单 我的项目界面- 新增房源 我的项目界面- 查找房源 我的项目界面- 删除房源 我的项目界面- 批改房源 我的项目界面- 屋宇列表 我的项目界面- 退出零碎 房屋出租零碎-设计(!!)我的项目设计-程序框架图(分层模式=>当软件比较复杂,须要模式治理) 房屋出租零碎-实现筹备工具类Utility,进步开发效率 在理论开发中,公司都会提供相应的工具类和开发库,能够进步开发效率,程序员也须要可能看懂他人写的代码,并可能正确的调用。 理解Utility 类的应用测试Utility 类我的项目性能实现-实现House 类编号 房主 电话 地址 月租 状态(未出租/已出租 package com.hspedu.houserent.domain;/** * House的对象示意一个房屋信息 */public class House { //编号 房主 电话 地址 月租 状态(未出租/已出租) private int id; private String name; private String phone; private String address; private int rent; private String state; //结构器和setter,getter public House(int id, String name, String phone, String address, int rent, String state) { this.id = id; this.name = name; this.phone = phone; this.address = address; this.rent = rent; this.state = state; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public int getRent() { return rent; } public void setRent(int rent) { this.rent = rent; } public String getState() { return state; } public void setState(String state) { this.state = state; } //为了不便的输入对象信息,咱们实现toString //编号 房主 电话 地址 月租 状态(未出租/已出租) @Override public String toString() { return id + "\t\t" + name + "\t" + phone + "\t\t" + address + "\t" + rent + "\t" + state ; }}我的项目性能实现-显示主菜单和实现退出软件性能实现性能的三部曲[明确实现性能->思路剖析->代码实现] ...

April 16, 2023 · 7 min · jiezi

关于java:浅谈我对-ChatGPT-AI-的一些使用理解

随着 ChatGPT 的大火,让中国本来有些寂静的 AI 行业又开始火爆起来。我记得第一次应用 ChatGPT 是 2022 年 12 月 初的时候,那个时候我工作中在大数据平台方面遇到了一个 Bug,尝试了很多方向始终解决不了,而后有个敌人倡议我尝试去问一下 ChatGPT。 而后就去网上买了一个共享账号去问了一下 ChatGPT ,我记得过后的答复尽管没有解决我的,然而它让我关上了眼界,感觉我靠,这个货色这么弱小的嘛,什么都会。 给你们看一下我当初平时怎么应用的 ChatGPT 的。案例1:有个需要是去一个网站外面找几张图片进行数据可视化剖析。 这样岂不是爽歪歪,而后我再基于它的答案去整合一下,再给多给它一些息,它还能够进一步去剖析出我想要的数据,这样就能够了。 如果要是依照咱们之前那种传统的办法去剖析,起码预计也要两天能力实现,当初是大大节俭了咱们的工作效率,剩下的时候不就能来摸鱼了嘛。案例2:咱们做数据库设计的时候,也能够用到。 连主外键都给你建好,那我要查某个业余,都给你查问好了。 这真的是爽歪歪啊,当然了咱们工作中可能建设的不是这这么简略的表,我就是举个例子,大家能够触类旁通就行,都是一样的。 案例3:写周报,这是最让人头疼的事件,然而也不必怕。 哈哈哈,而后略微改一下,上班上班。 在这里说一下,我演示的只是在我这个互联网行业的用法,其余工作行业的用法是一样的。大家能够齐全平移到本人的工作行业,触类旁通就行。就是 ChatGPT 这个货色它哪个行业都是能够的 上面来说说我对 ChatGPT & AI 的认识,我集体感觉前面 AI + 传统行业是将来几年的一个大的趋势,尽管我国当初在封 ChatGPT 的应用,然而封不了的,等待时间成熟,还是会凋谢的。因为好的货色你是封不住的。 我给你们说一组数据自从 ChatGPT 2022年 11 月份公布 以来,公布5 天之后注册人数超过 100w,到 2023年1月份的 ChatGPT 的注册人数 1个亿。大家可能没什么概念,此前突破这一记录的是 TikTok,就是抖音的国际版,它用了 9 个月的工夫。 另外提供ChatGPT的OpenAI网站流量爆炸性地增长了3572%,从1830万人次增长到6.72亿人次。ChatGPT的OpenAI跻身寰球TOP50网站。这些数据全部都是实在数据,官网公布的。 如果你仔细一点,你会发现只有对于 ChatGPT & AI 的话题关注度始终都居高不下。大家可能感觉这个没有什么,离咱们还很边远,其实不是的。我感觉可能是因为你在国内看到的少。 然而我当初在国外真的我看到是 ChatGPT 太火了。当初国内几个大厂也在开发和 ChatGPT 相似的产品,像百度的 文心一言,阿里的通义千问,华为的盘古,京东的 ChatDJ,商汤科技的名曰磋商 ...

April 15, 2023 · 1 min · jiezi

关于java:Java面向对象编程基础

类与对象类和对象的区别和分割类是形象的,概念的,代表一类事物,比方人类,猫类.., 即它是数据类型.对象是具体的,理论的,代表一个具体事物, 即是实例.类是对象的模板,对象是类的一个个体,对应一个实例对象在内存中存在模式! 字符串实质上是一个援用类型,依照jvm的规定会把字符串放在办法区的常量池两头。 栈中的是对象援用(对象名),实际上的对象在堆中。 // 创立Person 对象// p1 是对象名(对象援用)// new Person() 创立的对象空间(数据) 才是真正的对象Person p1 = new Person();// 对象的属性默认值,恪守数组规定:属性/成员变量/字段从概念或叫法上看: 成员变量 = 属性 = field(字段) (即成员变量是用来示意属性的,对立叫属性) class Car { String name;//属性, 成员变量, 字段field double price; String color; String[] master;//属性能够是根本数据类型,也能够是援用类型(对象,数组)}属性是类的一个组成部分,个别是根本数据类型, 也可是援用类型(对象,数组)。比方后面定义猫类的 int age 就是属性 注意事项和细节阐明 属性的定义语法同变量,示例:拜访修饰符属性类型属性名; 拜访修饰符: 管制属性的拜访范畴 有四种拜访修饰符public, proctected, 默认, private ,前面我会具体介绍属性如果不赋值,有默认值,规定和数组统一。如何创建对象先申明再创立 Cat cat ; //申明对象cat cat = new Cat(); //创立间接创立 Cat cat = new Cat();如何拜访属性根本语法 对象名.属性名; cat.name ;cat.age;cat.color; Person p1=new Person0;p1.age=10;p1.name="小明";Person p2=p1;//把p1赋给了p2,让p2指向p1System.out.println(p2.age);请问:p2.age到底是多少? 10 并画出内存图: ...

April 15, 2023 · 6 min · jiezi

关于java:Java-Stream常见用法汇总开发效率大幅提升

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址 如果拜访不了Github,能够拜访gitee地址。 gitee地址 Java8 新增的 Stream 流大大加重了咱们代码的工作量,然而 Stream 流的用法较多,理论应用的时候容易忘记,整顿一下供大家参考。 1. 概述Stream 应用一种相似用 SQL 语句从数据库查问数据的直观形式来对 Java 汇合运算和表白的高阶形象。 Stream API 能够极大进步 Java 程序员的生产力,让程序员写出高效率、洁净、简洁的代码。 这种格调将要解决的元素汇合看作一种流, 流在管道中传输, 并且能够在管道的节点上进行解决, 比方筛选, 排序,聚合等。 2. 创立2.1 汇合自带 Stream 流办法List<String> list = new ArrayList<>();// 创立一个程序流Stream<String> stream = list.stream();// 创立一个并行流Stream<String> parallelStream = list.parallelStream();2.1 通过 Array 数组创立最全面的Java面试网站int[] array = {1,2,3,4,5};IntStream stream = Arrays.stream(array);2.3 应用 Stream 的静态方法创立Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);Stream<Integer> stream = Stream.iterate(0, (x) -> x + 3).limit(3); // 输入 0,3,6Stream<String> stream = Stream.generate(() -> "Hello").limit(3); // 输入 Hello,Hello,HelloStream<Double> stream = Stream.generate(Math::random).limit(3); // 输入3个随机数2.3 数值流// 生成无限的常量流IntStream intStream = IntStream.range(1, 3); // 输入 1,2IntStream intStream = IntStream.rangeClosed(1, 3); // 输入 1,2,3// 生成一个等差数列IntStream.iterate(1, i -> i + 3).limit(5).forEach(System.out::println); // 输入 1,4,7,10,13// 生成有限常量数据流IntStream generate = IntStream.generate(() -> 10).limit(3); // 输入 10,10,10另外还有 LongStream、DoubleStream 都有这几个办法。 ...

April 14, 2023 · 2 min · jiezi

关于java:如何通过Java程序合并Word文档

合并Word文档是指将多个Word文档的内容、款式和格局合并成一个新的Word文档。这个性能通常在须要整合多个文档内容时应用,比方在对多个人员提交的文档进行汇总、审阅或编辑时。通过合并Word文档,能够大大提高工作效率,缩小手动复制粘贴等繁琐操作,同时保留原始文档的格局和款式,使得最终生成的合并文档看起来更加标准、好看。本文将介绍如何通过Free Spire.Doc for Java组件来合并Word文档。上面是具体方法和示例代码。 程序环境:IntelliJ IDEA 2018 (jdk 1.8.0)在进行操作之前先导入jar包,请参考以下两种导入形式:办法一:如果应用的是 maven,能够增加以下代码到我的项目的 pom.xml 文件中。 <repositories> <repository> <id>com.e-iceblue</id> <name>e-iceblue</name> <url>https://repo.e-iceblue.cn/repository/maven-public/</url> </repository></repositories><dependencies> <dependency> <groupId>e-iceblue</groupId> <artifactId>spire.doc.free</artifactId> <version>5.2.0</version> </dependency></dependencies>办法二:如果没有应用 maven,则能够从此链接下载Free Spire.Doc for Java,找到lib文件夹下的Spire.doc.jar并进行解压;而后在IDEA中创立一个新我的项目,顺次点击“文件”(File),“我的项目构造”(Project Structure),“组件”(Modules),“依赖项”(Dependencies),再点击右方绿色“+”下的第一个选项“jar文件或门路”(JARs or Directories),找到解压后的Spire.doc.jar 文件,点击确认,将其导入到我的项目中。 通过插入文档来合并文档这一办法是指在文档最初,新起一页插入另外的文档。 办法步骤:创立Document类的对象并加载一个示例文档。应用 Document.insertTextFromFile()办法将另一个 Word 文档齐全插入到加载的该文档。应用Document.saveToFile()办法保留后果文档。 例代码:import com.spire.doc.*;public class merge { public static void main(String[] args) { //创立Document对象并加载一个示例文档 Document document = new Document("sample1.docx"); //将另一个Word文档齐全插入到文档中 document.insertTextFromFile("sample2.docx", FileFormat.Docx_2013); //保留后果文档 document.saveToFile("result1.docx", FileFormat.Docx_2013); }} 通过复制内容来合并文档这一办法是指将文档内容插入到指定文档最初,不另起一页。 办法步骤:创立两个Document对象并加载两个示例文档。遍历第二个文档,通过Document.getSections()办法获取所有节。遍历所有节,通过Section.getBod().getChildObjects()办法以获取其子对象。应用 Document.getLastSection()办法获取第一个文档的最初一节。应用Body.getChildObjects().add()办法将子对象增加到第一个文档的最初一节中。应用Document.saveToFile()办法保留后果文档。 示例代码:import com.spire.doc.*;public class mergeDocuments { public static void main(String[] args){ //创立两个Document对象并加载两个示例文档 Document document1 = new Document("sample1.docx"); Document document2 = new Document("sample2.docx"); //遍历第二个文档,获取所有节 for (Object sectionObj : (Iterable) document2.getSections()) { Section sec=(Section)sectionObj; //遍历第二个文档的所有节,获取其子对象 for (Object docObj :(Iterable ) sec.getBody().getChildObjects()) { DocumentObject obj=(DocumentObject)docObj; //获取第一个文档的最初一节 Section lastSection = document1.getLastSection(); //将子对象增加到第一个文档的最初一节中 Body body = lastSection.getBody(); body.getChildObjects().add(obj.deepClone()); } } //保留后果文档 document1.saveToFile("result2.docx", FileFormat.Docx_2013); }} ...

April 14, 2023 · 1 min · jiezi

关于java:Java数组排序和查找

数组介绍数组能够寄存多个同一类型的数据。数组也是一种数据类型,是援用类型。 数组的应用应用形式1-动静初始化数组的定义数据类型数组名[]=new数据类型[大小] int a[] = new int[5];//创立了一个数组,名字a,寄存5个int阐明: 这是定义数组的一种办法。 import java.util.Scanner;public class Array02 { //编写一个main办法 public static void main(String[] args) { //演示 数据类型 数组名[]=new 数据类型[大小] //循环输出5个问题,保留到double数组,并输入 //步骤 //1. 创立一个 double 数组,大小 5 //(1) 第一种动态分配形式 //double scores[] = new double[5]; //(2) 第2种动态分配形式, 先申明数组,再 new 调配空间 double scores[] ; //申明数组, 这时 scores 是 null scores = new double[5]; // 分配内存空间,能够存放数据 //2. 循环输出 // scores.length 示意数组的大小/长度 // Scanner myScanner = new Scanner(System.in); for( int i = 0; i < scores.length; i++) { System.out.println("请输出第"+ (i+1) +"个元素的值"); scores[i] = myScanner.nextDouble(); } //输入,遍历数组 System.out.println("==数组的元素/值的状况如下:==="); for( int i = 0; i < scores.length; i++) { System.out.println("第"+ (i+1) +"个元素的值=" + scores[i]); } }}应用形式2-动静初始化1.先申明数组 ...

April 14, 2023 · 3 min · jiezi

关于java:Java程序控制结构

程序流程管制介绍顺序控制分支管制循环管制if 分支 switch 分支构造switch(表达式){ case常量1; 语句块1; break; case常量2; 语句块2; break; ... case常量n; 语句块n; break; default: default语句块; break;}表达式数据类型,应和case后的常量类型统一,或者是能够主动转成能够互相比拟的类型,比方输出的是字符,而常量是intswitch(表达式)中表达式的返回值必须是:(byte,short,int,char,enum[枚举],String) case子句中的值必须是常量,而不能是变量default子句是可选的,当没有匹配的case时,执行defaultbreak语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有写break,程序会程序执行到switch结尾,除非遇到break;for 循环管制for (循环变量初始化;循环条件;循环变量迭代){ 循环操作(能够多条语句);}while 循环管制while(循环条件){ 循环体(语句); 循环变量迭代;}do..while 循环管制do{ 循环体(语句); 循环变量迭代;}while(循环条件);跳转管制语句-breakbreak 语句用于终止某个语句块的执行,个别应用在switch 或者循环[for , while , do-while]中。 break语句呈现在多层嵌套的语句块中时,能够通过标签指明要终止的是哪一层语句块。如果没有指定break,默认退出最近的循环体 例:实现登录验证,有3 次机会,如果用户名为"丁真" ,明码"666"提醒登录胜利,否则提醒还有几次机会,请应用for+break import java.util.Scanner;public class BreakExercise02 { //编写一个main办法 public static void main(String[] args) { //实现登录验证,有3次机会,如果用户名为"丁真" ,明码"666"提醒登录胜利, //否则提醒还有几次机会,请应用for+break实现 // // 思路剖析 // 1. 创立Scanner对象接管用户输出 // 2. 定义 String name ; String passwd; 保留用户名和明码 // 3. 最多循环3次[登录3次],如果 满足条件就提前退出 // 4. 定义个别变量 int chance 记录还有几次登录机会 // // 代码实现 Scanner myScanner = new Scanner(System.in); String name = ""; String passwd = ""; int chance = 3; //登录一次 ,就缩小一次 for( int i = 1; i <= 3; i++) {//3次登录机会 System.out.println("请输出名字"); name = myScanner.next(); System.out.println("请输出明码"); passwd = myScanner.next(); //比拟输出的名字和明码是否正确 //补充阐明字符串 的内容 比拟 应用的 办法 equals // 字符串比拟举荐这种写法,能够无效防止空指针。相比于("name".equals(丁真)) if("丁真".equals(name) && "666".equals(passwd)) { System.out.println("祝贺你,登录胜利~"); break; } //登录的机会就缩小一次 chance--; System.out.println("你还有" + chance + "次登录机会"); } }}跳转管制语句-continuecontinue 语句用于完结本次循环,继续执行下一次循环。 ...

April 14, 2023 · 1 min · jiezi

关于java:从ReentrantLock角度解析AQS

是它,是它,就是它,并发包的基石;一、概述闲来不卷,轻易聊一点。 个别状况下,大家零碎中至多也是JDK8了,那想必对于JDK5退出的一系列性能并不生疏吧。那时候重点退出了java.util.concurrent并发包,咱们简称为JUC。JUC下提供了很多并发编程实用的工具类,比方并发锁lock、原子操作atomic、线程池操作Executor等等。上面,我对JUC做了整顿,大抵分为上面几点: 基于JDK8,明天重点来聊下JUC并发包下的一个类,AbstractQueuedSynchronizer。 首先,通俗的从名字上看,形象的队列同步器;实际上,这名字也跟它的作用一模一样。形象,即须要被继承;队列同步器,其外部保护了一个队列,供线程入队期待;最终实现多个线程访问共享资源的性能。 二、源码解析进入AbstractQueuedSynchronizer外部,须要把握三个重要的属性: private transient volatile Node head;private transient volatile Node tail;private volatile int state;head:标记期待队列头部节点。tail:标记期待队列尾部节点。state:线程的锁定状态;state=0,示意资源未被上锁;state>0,示意资源被上锁咱们调试AQS的源码,必须寻找一个源码调试的切入点,我这里用咱们并发编程罕用的Lock锁作为调试AQS的切入点,因为这是解决线程平安问题罕用的伎俩之一。 2.1、源码的切入点AQS的源码调试,从Lock接口登程,JDK源码定义如下: public interface Lock { void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock(); boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock(); Condition newCondition();}从源码中看到,Lock是一个接口,所以该接口会有一些实现类,其中有一个实现类ReentrantLock,可重入锁,想必大家都不会生疏。 2.2、ReentrantLock的lock办法通过跟踪源码能够看到,ReentrantLock#lock外部实现貌似比较简单,只有简短的一行代码 public void lock() { sync.lock();}其实外部是保护了一个Sync的抽象类,调用的是Sync的lock()办法。 abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; abstract void lock(); final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; } protected final boolean isHeldExclusively() { return getExclusiveOwnerThread() == Thread.currentThread(); } // ...}能够看到,Sync也是个抽象类,它有两个实现类:NonfairSync和FairSync,这里其实就引出了咱们明天的配角,AbstractQueuedSynchronizer,Sync继承了它。 ...

April 14, 2023 · 7 min · jiezi

关于java:Java里的数据类型都有哪些

相干面试题咱们从学习Java开始,很快就会遇到 Java中的数据类型 这个问题。对于数据类型,对于初学者来说,很容易记混,因为Java中的数据类型划分的有点多。所以在招聘高级程序员时,面试官就会常常在这一块出一些题目,对求职者进行根底语法方面的考核。常见的数据类型相干的面试题如下: 请说一下Java中有哪些数据类型? Java中有哪些根本数据类型? 根本数据类型的取值范畴是多大? Java的2个字节占多少位? int占几个字节? 数据类型之间怎么进行转换? ...... 当然对于下面这些面试题,并不一定就这么问,很多时候面试官可能会把题干进行批改,但考查的内容其实还是这些内容。总之,万变不离其宗,Java里的知识点就那些货色,再怎么问,也都是这些内容。 本篇文章会带大家来温习Java中的数据类型,这些内容个别都是以记忆为主! 一. 题目剖析以上这些题目,其实都是围绕着Java中的数据类型来进行发问的,考查的重点就是求职者对数据类型的掌握情况。因为Java中数据类型分类较多,初学者容易记混,并且在数据类型这一块又波及到类型转换,开发时有可能会因为类型转换导致一些bug。另外咱们在编写代码时,不同的变量也应该抉择适合的数据类型,这样有利于优化内存调配。 所以面试官针对这些来发问,目标就是在考查求职者的语言根底是否扎实。 二. Java中的数据类型咱们在接触任何一种编程语言时,都会存在对数据类型的意识,有简单的,也有简略的。这些数据类型都须要咱们在学习初期去理解和把握,所以各位请跟着 壹哥 来看看对于数据类型的常识吧。 动态类型和强类型因为Java语言是 动态类型的(statical typed) , 也就是说Java中的所有变量和表达式的类型,在编译时就曾经齐全确定了。所以咱们在应用变量时,必须先申明其类型,即在创立的那一刻就曾经确定好了该变量的类型。在前面的应用中,你只能将这一指定类型的数据赋值给该变量,如果强行将其余不相干类型的数据赋值给它,就会引发谬误。比方一旦申明了一个int类型的变量,那么之后就只能将int类型的数据赋值给它,否则就会引发谬误。因为Java是动态类型statical typed的语言,这也就导致了Java是 强类型(Strong typed) 的语言,因为语言的强弱体现在对类型的查看严格与否上。 弱类型语言对于变量类型的查看比拟宽松,容忍隐式类型转换这种事件的产生,强类型则反之。所以强类型意味着每个变量都必须具备一种类型,每个表达式也都必须具备一种类型,并且每种类型都是有严格定义的。类型限度了该变量能够持有存储哪类值,表达式最终产生什么类型的值,同时也限度了这些值能够进行的操作类型以及操作的具体形式。所有的赋值操作,无论是显式的、还是在办法调用中通过参数传递的,都要进行类型的兼容性查看。 数据类型概念当初通过下面壹哥对动态类型和强类型概念的介绍后,咱们就能够很好的了解数据类型的概念了。所谓的数据类型,在计算机语言外面,咱们能够把它了解成是针对内存地位的一种形象的表达方式。简略的来说,数据类型就是对数据的一种分类,依据每种数据各自的特点进行类别的划分,每种数据类型都与其余类型不同。 举个栗子:咱们能够把不同的数据类型了解为存储在不同箱子里的不同类别的内容,有的箱子里只能装固体,有的箱子里只能装液体,有的箱子里只能装气体......这些箱子会寄存在不同的中央,外面的货色也不能混装,每个箱子里的货色也都属于不同的分类。 数据类型分类在Java外面,整体上把数据类型分成了两大类:根本类型(primitive types) 8个 和 援用类型(reference types) 5个,咱们来看一张残缺的分类图,如下所示: 接下来我会对根本类型和援用类型别离进行介绍。 3.1 根本类型根本类型 是Java中预约义的类型,有相应的保留关键字来示意,具备明确的取值范畴和数学行为, 示意了实在的数字、字符和整数。根本类型的数据都是单个值,不是简单的对象,所以根本类型并不是面向对象的,这次要是出于效率方面的思考。但同时Java中也为根本类型提供了对应的对象版本,即根本类型的包装类(wrapper)。咱们能够间接应用这些根本类型,也能够应用根本类型的结构数组或者其余自定义类型。 根本类型 包含布尔(boolean)类型、数值类型(numeric types),数值类型又分为 整型(integer types) 和 浮点型(floating-point type) 。整型有5种:byte、short、int、long、char(char实质上是一种非凡的int);浮点类型有float和double。所以根本数据类型分类如下: byte、short、int、long、float(单精度)、double(双精度)、char、boolean 根本类型具体信息表: 3.2 援用类型援用类型(The value of reference types are references to objects)中的援用,个别是指某个对象的内存地址,其中对象是动态创建的类实例或者动态创建的数组。另外Java语言自身不反对C++中的构造体(struct) 或联合体(union) 等数据类型,这种复合数据类型个别都是通过类或接口进行结构 。 援用数据类型分类如下: 类、接口、数组、枚举、注解 ...

April 13, 2023 · 2 min · jiezi

关于java:RocketMQ是是如何管理消费进度的又是如何保证消息成功消费的

RocketMQ消费者保障 作者: 博学谷狂野架构师GitHub:GitHub地址 (有我精心筹备的130本电子书PDF) 只分享干货、不吹水,让咱们一起加油!音讯确认机制consumer的每个实例是靠队列调配来决定如何生产音讯的。那么生产进度具体是如何治理的,又是如何保障音讯胜利生产的?(RocketMQ有保障音讯必定生产胜利的个性,失败则重试)什么是ACK音讯确认机制在理论应用RocketMQ的时候咱们并不能保障每次发送的音讯都刚好能被消费者一次性失常生产胜利,可能会存在须要屡次生产能力胜利或者始终生产失败的状况,那作为发送者该做如何解决呢? 为了保证数据不被失落,RocketMQ反对音讯确认机制,即ack。发送者为了保障音讯必定生产胜利,只有应用方明确示意生产胜利,RocketMQ才会认为音讯生产胜利。中途断电,抛出异样等都不会认为胜利——即都会从新投递。 保证数据能被正确处理而不仅仅是被Consumer收到,咱们就不能采纳no-ack或者auto-ack,咱们须要手动ack(manual-ack)。在数据处理实现后手动发送ack,这个时候Server才将Message删除。 RocketMQ ACK因为以上工作所有的机制都实现在PushConsumer中,所以本文的原理均只实用于RocketMQ中的PushConsumer即Java客户端中的DefaultPushConsumer。 若应用了PullConsumer模式,相似的工作如何ack,如何保障生产等均须要应用方本人实现。 注:播送生产和集群生产的解决有局部区别,以下均特指集群生产(CLSUTER),播送(BROADCASTING)下局部可能不实用。 保障生产胜利PushConsumer为了保障音讯必定生产胜利,只有应用方明确示意生产胜利,RocketMQ才会认为音讯生产胜利。中途断电,抛出异样等都不会认为胜利——即都会从新投递。代码示例生产的时候,咱们须要注入一个生产回调,具体sample代码如下:COPYconsumer.registerMessageListener(new MessageListenerConcurrently() { @Override public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { System.out.println(Thread.currentThread().getName() + " Receive New Messages: " + msgs); execute();//执行真正生产 return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } });业务实现生产回调的时候,当且仅当此回调函数返回ConsumeConcurrentlyStatus.CONSUME_SUCCESS,RocketMQ才会认为这批音讯(默认是1条)是生产实现的。 如果这时候音讯生产失败,例如数据库异样,余额有余扣款失败等所有业务认为音讯须要重试的场景,只有返回ConsumeConcurrentlyStatus.RECONSUME_LATER,RocketMQ就会认为这批音讯生产失败了。 为了保障音讯是必定被至多生产胜利一次,RocketMQ会把这批音讯重发回Broker(topic不是原topic而是这个生产租的RETRY topic),在提早的某个工夫点(默认是10秒,业务可设置)后,再次投递到这个ConsumerGroup。而如果始终这样反复生产都继续失败到肯定次数(默认16次),就会投递到DLQ死信队列。利用能够监控死信队列来做人工干预。 ACK进度保留启动的时候从哪里生产当新实例启动的时候,PushConsumer会拿到本生产组broker曾经记录好的生产进度(consumer offset),依照这个进度发动本人的第一次Pull申请。 如果这个生产进度在Broker并没有存储起来,证实这个是一个全新的生产组,这时候客户端有几个策略能够抉择: COPYCONSUME_FROM_LAST_OFFSET //默认策略,从该队列最尾开始生产,即跳过历史音讯CONSUME_FROM_FIRST_OFFSET //从队列最开始开始生产,即历史音讯(还贮存在broker的)全副生产一遍CONSUME_FROM_TIMESTAMP//从某个工夫点开始生产,和setConsumeTimestamp()配合应用,默认是半个小时以前所以,社区中常常有人问:“为什么我设了CONSUME_FROM_LAST_OFFSET,历史的音讯还是被生产了”? 起因就在于只有全新的生产组才会应用到这些策略,老的生产组都是按曾经存储过的生产进度持续生产。 对于老生产组想跳过历史音讯须要本身做过滤,或者应用先批改生产进度 音讯ACK生产进度RocketMQ是以consumer group+queue为单位是治理生产进度的,以一个consumer offset标记这个这个生产组在这条queue上的生产进度。如果某已存在的生产组呈现了新生产实例的时候,依附这个组的生产进度,就能够判断第一次是从哪里开始拉取的,每次音讯胜利后,本地的生产进度会被更新,而后由定时器定时同步到broker,以此长久化生产进度。 然而每次记录生产进度的时候,只会把一批音讯中最小的offset值为生产进度值,如下图: 这钟形式和传统的一条message独自ack的形式有实质的区别。性能上晋升的同时,会带来一个潜在的反复问题——因为生产进度只是记录了一个下标,就可能呈现拉取了100条音讯如 2101-2200的音讯,前面99条都生产完结了,只有2101生产始终没有完结的状况。 在这种状况下,RocketMQ为了保障音讯必定被生产胜利,生产进度职能维持在2101,直到2101也生产完结了,本地的生产进度能力标记2200生产完结了(注:consumerOffset=2201)。 反复生产在这种设计下,就有生产大量反复的危险。如2101在还没有生产实现的时候生产实例忽然退出(机器断电,或者被kill)。这条queue的生产进度还是维持在2101,当queue重新分配给新的实例的时候,新的实例从broker上拿到的生产进度还是维持在2101,这时候就会又从2101开始生产,2102-2200这批音讯实际上曾经被生产过还是会投递一次。 对于这个场景,RocketMQ临时无能为力,所以业务必须要保障音讯生产的幂等性,这也是RocketMQ官网屡次强调的态度。 实际上,从源码的角度上看,RocketMQ可能是思考过这个问题的,截止到3.2.6的版本的源码中,能够看到为了缓解这个问题的影响面,DefaultMQPushConsumer中有个配置consumeConcurrentlyMaxSpan COPY/** * Concurrently max span offset.it has no effect on sequential consumption */private int consumeConcurrentlyMaxSpan = 2000;这个值默认是2000,当RocketMQ发现本地缓存的音讯的最大值-最小值差距大于这个值(2000)的时候,会触发流控——也就是说如果头尾都卡住了局部音讯,达到了这个阈值就不再拉取音讯。 ...

April 13, 2023 · 5 min · jiezi

关于java:Java分布式架构设计与开发实战2022全新版惟草木之零落兮

download:Java分布式架构设计与开发实战2022全新版Python是一种高级编程语言,具备简略易学、可读性强、可扩展性强等长处,曾经成为许多开发人员的首选语言。本文将介绍Python的基本概念、利用场景以及一些最佳实际。 Python的基本概念 语法简洁Python的语法简洁易懂,与其余编程语言相比,Python能够大大减少代码行数,进步编写效率。 面向对象编程Python是一种面向对象的编程语言,它反对封装、继承和多态等面向对象编程的个性。 动静类型Python是一种动静类型语言,不须要当时申明变量类型。这意味着您能够更快地编写代码,但须要留神类型转换和错误处理。 具备丰盛的库和框架Python领有丰盛的规范库和第三方库,能够满足各种需要。例如,NumPy、Pandas、Matplotlib等用于数据分析和可视化的库,Django和Flask等用于Web开发的框架。 Python的利用场景 Python能够利用于许多畛域,以下是一些常见的利用场景: 数据迷信Python是数据迷信中的次要编程语言之一。它能够用于数据荡涤、数据分析、机器学习和人工智能等畛域。 Web开发Python领有许多优良的Web框架,例如Django、Flask和Bottle等,能够用于Web开发、API开发和后端开发等畛域。 自动化测试Python是自动化测试中罕用的编程语言。它能够用于测试脚本编写、Web UI测试和API测试等畛域。 游戏开发Python能够用于游戏开发,例如开发基于Pygame的游戏。此外,Python还能够用于开发游戏服务器和游戏AI等方面。 Python的最佳实际 以下是一些Python最佳实际,有助于编写更好的Python代码: 遵循PEP 8标准PEP 8是Python的编码标准,倡议遵循这个标准编写Python代码。 应用虚拟环境虚拟环境能够帮忙您隔离不同我的项目之间的依赖关系。能够应用venv或conda等工具创立虚拟环境。 应用适合的库和框架Python领有泛滥库和框架,但不是所有的都实用于您的我的项目。抉择适合的库和框架能够进步代码的质

April 13, 2023 · 1 min · jiezi

关于java:Java运算符标识符以及进制

文章和代码曾经归档至【Github仓库:https://github.com/timerring/java-tutorial 】或者公众号【AIShareLab】回复 java 也可获取。运算符介绍算术运算符赋值运算符关系运算符逻辑运算符位运算符三元运算符算术运算符 关系运算符(比拟运算符)关系运算符的后果都是boolean 型,也就是要么是true,要么是false 逻辑运算符用于连贯多个条件(多个关系表达式),最终的后果也是一个boolean 值。 短路与&& , 短路或||,取反!逻辑与&,逻辑或|,^ 逻辑异或赋值运算符赋值运算符的分类根本赋值运算符 = 复合赋值运算符+= ,-= ,*= , /= ,%= 等, 重点解说一个+= ,其它的应用是一个情理 赋值运算符特点复合赋值运算符会进行类型转换 byte b = 2; b+=3; b++; 三元运算符根本语法条件表达式? 表达式1: 表达式2;运算规定: 如果条件表达式为true,运算后的后果是表达式1;如果条件表达式为false,运算后的后果是表达式2;应用细节表达式1 和表达式2 要为能够赋给接管变量的类型(或能够主动转换)三元运算符能够转成if--else 语句运算符优先级运算符有不同的优先级,所谓优先级就是表达式运算中的运算程序。如右表,上一行运算符总优先于下一行。只有单目运算符、赋值运算符是从右向左运算的。 标识符的命名规定和标准标识符概念 Java对各种变量、办法和类等命名时应用的字符序列称为标识符 标识符的命名规定 由26个英文字母大小写,0-9,或$组成数字不能够结尾。不能够应用关键字和保留字,但能蕴含关键字和保留字。Java中严格辨别大小写,长度无限度标识符不能蕴含空格。int a b = 90;标识符命名标准包名:多单词组成时所有字母都小写:aaa.bbb.ccc //比方com.hsp.crm类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz [大驼峰]比方: TankShotGame变量名、办法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz [小驼峰, 简称驼峰法]比方: tankShotGame常量名:所有字母都大写。多单词时每个单词用下划线连贯:XXX_YYY_ZZZ比方:定义一个所得税率TAX_RATE前面咱们学习到类,包,接口,等时,咱们的命名标准要这样恪守,更加具体的看文档.关键字关键字的定义和特点 定义:被Java 语言赋予了非凡含意,用做专门用处的字符串 特点:关键字中所有字母都为小写 保留字Java 保留字:现有Java 版本尚未应用,但当前版本可能会作为关键字应用。本人命名标识符时要防止应用这些保留字byValue、cast、future、generic、inner、operator、outer、rest、var 、goto 、const 键盘输入语句在编程中,须要接管用户输出的数据,就能够应用键盘输入语句来获取。Input.java , 须要一个扫描器(对象), 就是Scanner 导入该类的所在包, java.util.*创立该类对象(申明变量)调用外面的性能import java.util.Scanner;//示意把java.util下的Scanner类导入 public class Input { //编写一个main办法 public static void main(String[] args) { //演示承受用户的输出 //Scanner类 示意 简略文本扫描器,在java.util 包 //1. 引入/导入 Scanner类所在的包 //2. 创立 Scanner 对象 , new 创立一个对象,领会myScanner 就是 Scanner类的对象 Scanner myScanner = new Scanner(System.in); //3. 接管用户输出了, 应用 相干的办法 System.out.println("请输出名字"); //当程序执行到 next 办法时,会期待用户输出~~~ String name = myScanner.next(); //接管用户输出字符串 System.out.println("请输出年龄"); int age = myScanner.nextInt(); //接管用户输出int System.out.println("请输出薪水"); double sal = myScanner.nextDouble(); //接管用户输出double System.out.println("人的信息如下:"); System.out.println("名字=" + name + " 年龄=" + age + " 薪水=" + sal); }}进制对于整数,有四种示意形式:二进制:0,1 ,满2 进1 以0b 或0B 结尾。十进制:0-9 ,满10 进1。八进制:0-7 ,满8 进1. 以数字0 结尾示意。十六进制:0-9 及A(10)-F(15),满16 进1. 以0x 或0X 结尾示意。此处的A-F 不辨别大小写。 ...

April 13, 2023 · 2 min · jiezi

关于java:一天吃透MySQL面试八股文

什么是MySQLMySQL是一个关系型数据库,它采纳表的模式来存储数据。你能够了解成是Excel表格,既然是表的模式存储数据,就有表构造(行和列)。行代表每一行数据,列代表该行中的每个值。列上的值是有数据类型的,比方:整数、字符串、日期等等。 数据库的三大范式第一范式1NF 确保数据库表字段的原子性。 比方字段 userInfo: 广东省 10086' ,按照第一范式必须拆分成 userInfo: 广东省 userTel: 10086两个字段。 第二范式2NF 首先要满足第一范式,另外蕴含两局部内容,一是表必须有一个主键;二是非主键列必须齐全依赖于主键,而不能只依赖于主键的一部分。 举个例子。假设选课关系表为student_course(student_no, student_name, age, course_name, grade, credit),主键为(student_no, course_name)。其中学分齐全依赖于课程名称,姓名年龄齐全依赖学号,不合乎第二范式,会导致数据冗余(学生选n门课,姓名年龄有n条记录)、插入异样(插入一门新课,因为没有学号,无奈保留新课记录)等问题。 应该拆分成三个表:学生:student(stuent_no, student_name, 年龄);课程:course(course_name, credit);选课关系:student_course_relation(student_no, course_name, grade)。 第三范式3NF 首先要满足第二范式,另外非主键列必须间接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的状况。 假设学生关系表为Student(student_no, student_name, age, academy_id, academy_telephone),主键为"学号",其中学院id依赖于学号,而学院地点和学院电话依赖于学院id,存在传递依赖,不合乎第三范式。 能够把学生关系表分为如下两个表:学生:(student_no, student_name, age, academy_id);学院:(academy_id, academy_telephone)。 2NF和3NF的区别? 2NF根据是非主键列是否齐全依赖于主键,还是依赖于主键的一部分。3NF根据是非主键列是间接依赖于主键,还是间接依赖于非主键。本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址 如果拜访不了Github,能够拜访gitee地址。 gitee地址 事务的四大个性?事务个性ACID:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。 原子性是指事务蕴含的所有操作要么全副胜利,要么全副失败回滚。一致性是指一个事务执行之前和执行之后都必须处于一致性状态。比方a与b账户共有1000块,两人之间转账之后无论胜利还是失败,它们的账户总和还是1000。隔离性。跟隔离级别相干,如read committed,一个事务只能读到曾经提交的批改。持久性是指一个事务一旦被提交了,那么对数据库中的数据的扭转就是永久性的,即使是在数据库系统遇到故障的状况下也不会失落提交事务的操作。事务隔离级别有哪些?先理解下几个概念:脏读、不可反复读、幻读。 脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。不可反复读是指在对于数据库中的某行记录,一个事务范畴内屡次查问却返回了不同的数据值,这是因为在查问距离,另一个事务批改了数据并提交了。幻读是当某个事务在读取某个范畴内的记录时,另外一个事务又在该范畴内插入了新的记录。对幻读的正确理解是一个事务内的读取操作的论断不能撑持之后业务的执行。假如事务要新增一条记录,主键为id,在新增之前执行了select,没有发现id为xxx的记录,但插入时呈现主键抵触,这就属于幻读,读取不到记录却发现主键抵触是因为记录实际上曾经被其余的事务插入了,但以后事务不可见。不可反复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可反复读则是读取了前一事务提交的数据。 事务隔离就是为了解决下面提到的脏读、不可反复读、幻读这几个问题。 MySQL数据库为咱们提供的四种隔离级别: Serializable (串行化):通过强制事务排序,使之不可能互相抵触,从而解决幻读问题。Repeatable read (可反复读):MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行,解决了不可反复读的问题。Read committed (读已提交):一个事务只能看见曾经提交事务所做的扭转。可防止脏读的产生。Read uncommitted (读未提交):所有事务都能够看到其余未提交事务的执行后果。查看隔离级别: select @@transaction_isolation;设置隔离级别: set session transaction isolation level read uncommitted;生产环境数据库个别用的什么隔离级别呢?生产环境大多应用RC。为什么不是RR呢? ...

April 13, 2023 · 6 min · jiezi

关于java:串行流Stream和并行流parallelStream的区别

1.Stream 是在 Java8 新增的个性,广泛称其为流;它不是数据结构也不寄存任何数据,其次要用于汇合的逻辑解决。 2.Stream流是一个汇合元素的函数模型,它并不是汇合,也不是数据结构,其自身并不存储任何元素(或其地址值),它只是在原数据集上定义了一组操作。 3.Stream流不保留数据,Stream操作是尽可能惰性的,即每当拜访到流中的一个元素,才会在此元素上执行这一系列操作。 4.Stream流不会扭转原有数据,想要拿到扭转后的数据,要用对象接管。 串行流stream:串行解决数据,不产生异步线程。并行流parallelStream:parallelStream提供了流的并行处理,它是Stream的另一重要个性,其底层应用Fork/Join框架实现。简略了解就是多线程异步工作的一种实现。 倡议:数据量不大的状况下倡议应用stream即可,不要自觉大量应用parallelStream,因为parallelStream是多线程异步的,也就是说会产生多线程,耗费内存不说,说不定还会更慢,并非肯定会更快更好。 上面说说罕用的几种办法:1.groupingBy办法:次要是转化数据为Map,value是符合条件的汇合 // 增加的洽购申请id汇合 List<PurchaseRequisition> requisitionList = new ArrayList<>(); Map<String, List<PurchaseRequisitionSkuParams>> skuMap = requisitionParams.getSkuList().stream().collect(Collectors.groupingBy(PurchaseRequisitionSkuParams::getBrandName)); skuMap.forEach((brandName,skus)->{ // 生成洽购申请编码 purchaseRequisition.setPurchaseRequisitionCode(purchaseCodeUtil.getNextPurchaseCode()); // 保留洽购信息 requisitionMapper.savePurchaseRequisition(purchaseRequisition); requisitionList.add(purchaseRequisition); // 保留洽购物料明细 requisitionMapper.saveSkuList(purchaseRequisition.getId(),skus); });2.toMap办法:次要是转化数据为Map,value是该条记录或字段值 // sku数量校验 Map<String, BigDecimal> skuNumMap = requisitionParams.getSkuList().stream().collect( Collectors.toMap(PurchaseRequisitionSkuParams::getSkuId,PurchaseRequisitionSkuParams::getNum,(v1,v2) -> v1.add(v2))); // 查出购买的数量 List<CustomerOderSkuNumVO> numVOList = customerOrderMapper.querySkuNum(requisitionParams.getCustomerOrderId(), skuNumMap.keySet()); numVOList.stream().forEach(numVO ->{ if (skuNumMap.get(numVO.getSkuId()).compareTo(numVO.getNum()) > 0){ throw new ValidateException(ApiResponseCode.ABNORMAL_DATA.getCode(), "洽购的物料数量不能大于客户订单数量!"); } });3.filter办法:次要是用来筛选数据的 List<Admin> adminList = adminMapper.selectList(null); adminList = adminList.stream().filter(admin -> admin.getAdminState() != null).collect(Collectors.toList());4.anyMatch办法:用于判断数据,只有有一个条件满足即返回true ...

April 12, 2023 · 1 min · jiezi

关于java:如何保证-Java-应用安全标准答案来了

“请问我怎么能力保障 Java 程序内存中明码的平安呢?” 如果你也过有相似的问题,并且在网上搜到一些并不非常欠缺却又无可奈何的答案,阐明你就是 Java 程序安全性问题的 stakeholder。 这个问题的标准答案是 Java 秘密计算技术,它将秘密计算技术引入 Java 的世界,为 Java 程序的安全性带来了重大的晋升。基于此,龙蜥社区云原生秘密计算 SIG 推出了 Java 秘密计算的具体实现技术——Teaclave Java TEE SDK, 以下简称 Teaclave Java。该技术具备以下显著长处: 全场景安全性。当用户有秘密计算硬件反对时,Teaclave Java 能够实现最高安全等级的 Java 可信计算;当用户没有相干硬件时,进化为平安沙箱隔离级别的可信计算,亦可无效爱护用户的敏感数据和计算过程的安全性。开发和构建简略。基于 SPI 的纯 Java 编程模型,一键式构建,将 Java 秘密计算开发构建门槛一降到底。Teaclave Java 曾经过企业级外部场景的验证,在 Apache 社区开源。形容本技术的论文由龙蜥社区云原生秘密计算 SIG 与上海交通大学、大连理工大学单干发表在软件工程顶会 ICSE 2023(https://conf.researchr.org/home/icse-2023)上,并且取得了本届会议的 ACM SIGSOFT 卓越论文奖。这是 2020 年以来,龙蜥社区云原生秘密计算 SIG、上海交通大学、大连理工大学首次获此殊荣。 01 问题的实质这个问题的实质是如何在具备危险的运行时环境中平安地应用敏感数据。当咱们在运行时将明码解密后,明码就会以明文的模式存在于内存中,也就是 Java 的堆上,如图 1 的左半局部所示。如果零碎蒙受攻打,比方 2021 年声名大噪的 log4j 破绽攻打,Java 堆上的内容就会被窃取。即使没有被攻打,在为了性能诊断而做 heap dump 时也有可能被动将敏感信息透露进来。所以将诸如明码这样的平安敏感信息裸露在一般运行环境具备高度的危险。 (解图 1 奢侈的 Java 密码保护示意图) 一种爱护思路是尽可能地缩短明文明码在内存中的寄存工夫,以缩短敏感信息裸露的工夫窗口。如图 1 右半局部所示,在应用完明码后,及时将其从内存中销毁,这样会比先前更加平安一些。因为明码是文本信息,会用字符串类 java.lang.String 保留。Java 的 String 是一种 immutable 类型,创立后不能更改内容,所以没有能够重置内容的 API。要销毁明码只能通过反射将 String 类外部保留字符内容的数组内容置空,从而将明码内容从 Java 堆上抹去。间接将明码字符串设置为 null 是没有用的,这样只是把 String 变量的指针设为空,对于 Java 堆上的明码数据没有任何影响,只有等到下次垃圾回收时才有可能将明码数据从堆中革除。另一种办法是用 char 数组保留明码,而不是 String 类,这样就不用调用反射,让销毁更加便当。还有一种办法是用 byte 数组保留明码,因为其明文是字符编码而非人可读的字符,所以会更难被人看懂。 ...

April 12, 2023 · 6 min · jiezi

关于java:小心丢失的消息RocketMQ投递策略帮你解决问题博学谷狂野架构师

RocketMQ音讯投递策略 作者: 博学谷狂野架构师GitHub:GitHub地址 (有我精心筹备的130本电子书PDF) 只分享干货、不吹水,让咱们一起加油!前言RocketMQ的音讯投递分分为两种:一种是生产者往MQ Broker中投递;另外一种则是MQ broker 往消费者 投递(这种投递的说法是从消息传递的角度论述的,实际上底层是消费者从MQ broker 中Pull拉取的)。本文将从模型的角度来论述这两种机制。 RocketMQ的音讯模型RocketMQ 的音讯模型整体并不简单,如下图所示: 一个Topic(音讯主题)可能对应多个理论的音讯队列(MessgeQueue) 在底层实现上,为了进步MQ的可用性和灵活性,一个Topic在理论存储的过程中,采纳了多队列的形式,具体模式如上图所示。每个音讯队列在应用中该当保障先入先出(FIFO,First In First Out)的形式进行生产。 那么,基于这种模型,就会引申出两个问题:生产者 在发送雷同Topic的音讯时,音讯体该当被搁置到哪一个音讯队列(MessageQueue)中?消费者 在生产音讯时,该当从哪些音讯队列中拉取音讯?音讯的零碎间传递时,会逾越不同的网络载体,这会导致音讯的流传无奈保障其有序请 生产者投递策略轮询算法投递默认投递形式:基于Queue队列轮询算法投递默认状况下,采纳了最简略的轮询算法,这种算法有个很好的个性就是,保障每一个Queue队列的音讯投递数量尽可能平均,算法如下图所示: COPY/*** 依据 TopicPublishInfo Topic公布信息对象中保护的index,每次抉择队列时,都会递增* 而后依据 index % queueSize 进行取余,达到轮询的成果**/public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName) { return tpInfo.selectOneMessageQueue(lastBrokerName);}/*** TopicPublishInfo Topic公布信息对象中*/public class TopicPublishInfo { //基于线程上下文的计数递增,用于轮询目标 private volatile ThreadLocalIndex sendWhichQueue = new ThreadLocalIndex(); public MessageQueue selectOneMessageQueue(final String lastBrokerName) { if (lastBrokerName == null) { return selectOneMessageQueue(); } else { int index = this.sendWhichQueue.getAndIncrement(); for (int i = 0; i < this.messageQueueList.size(); i++) { //轮询计算 int pos = Math.abs(index++) % this.messageQueueList.size(); if (pos < 0) pos = 0; MessageQueue mq = this.messageQueueList.get(pos); if (!mq.getBrokerName().equals(lastBrokerName)) { return mq; } } return selectOneMessageQueue(); } } public MessageQueue selectOneMessageQueue() { int index = this.sendWhichQueue.getAndIncrement(); int pos = Math.abs(index) % this.messageQueueList.size(); if (pos < 0) pos = 0; return this.messageQueueList.get(pos); }}代码示例RocketMQ默认采纳轮询投递策略COPY/** * 轮询投递策略 */public class PollingProducer { public static void main(String[] args) throws Exception { //创立一个音讯生产者,并设置一个音讯生产者组 DefaultMQProducer producer = new DefaultMQProducer("rocket_test_consumer_group"); //指定 NameServer 地址 producer.setNamesrvAddr("127.0.0.1:9876"); //初始化 Producer,整个利用生命周期内只须要初始化一次 producer.start(); for (int i = 0; i < 10; i++) { //创立一条音讯对象,指定其主题、标签和音讯内容 Message msg = new Message( /* 音讯主题名 */ "topicTest", /* 音讯标签 */ "TagA", /* 音讯内容 */ ("Hello Java demo RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) ); //发送音讯并返回后果 SendResult sendResult = producer.send(msg); System.out.println("product: 发送状态:" + sendResult.getSendStatus() + ",存储queue:" + sendResult.getMessageQueue().getQueueId() + ",音讯索引:" + i); } // 一旦生产者实例不再被应用则将其敞开,包含清理资源,敞开网络连接等 producer.shutdown(); }}打印后果COPYproduct: 发送状态:SEND_OK,存储queue:0,音讯索引:0product: 发送状态:SEND_OK,存储queue:1,音讯索引:1product: 发送状态:SEND_OK,存储queue:2,音讯索引:2product: 发送状态:SEND_OK,存储queue:3,音讯索引:3product: 发送状态:SEND_OK,存储queue:0,音讯索引:4product: 发送状态:SEND_OK,存储queue:1,音讯索引:5product: 发送状态:SEND_OK,存储queue:2,音讯索引:6product: 发送状态:SEND_OK,存储queue:3,音讯索引:7product: 发送状态:SEND_OK,存储queue:0,音讯索引:8product: 发送状态:SEND_OK,存储queue:1,音讯索引:9音讯投递提早最小策略默认投递形式的加强:基于Queue队列轮询算法和音讯投递提早最小的策略投递默认的投递形式比较简单,然而也裸露了一个问题,就是有些Queue队列可能因为本身数量积压等起因,可能在投递的过程比拟长,对于这样的Queue队列会影响后续投递的成果。 ...

April 12, 2023 · 9 min · jiezi

关于java:Java变量与数据类型

文章和代码曾经归档至【Github仓库:https://github.com/timerring/java-tutorial 】或者公众号【AIShareLab】回复 java 也可获取。第3章 变量程序中+号的应用1.当左右两边都是数值型时,则做加法运算 2.当左右两边有一方为字符串,则做拼接运算 数据类型 java 数据类型分为两大类根本数据类型 与 援用类型 根本数据类型有8种数值型[byte , short , int , long , float ,double]charboolean援用类型[类,接口, 数组]整数类型整型的类型 整型的应用细节IntDetail.javaJava各整数类型有固定的范畴和字段长度,不受具体OS[操作系统]的影响,以保障java程序的可移植性。Java的整型常量(具体值)默认为int型,申明long型常量须后加l或L 浮点类型浮点型的分类 对于浮点数在机器中寄存模式的简略阐明, 浮点数=符号位+指数位+尾数位尾数局部可能失落,造成精度损失(小数都是近似值)。浮点型应用细节FloatDetail.java与整数类型相似,Java浮点类型也有固定的范畴和字段长度,不受具体OS的影响。 Java的浮点型常量(具体值)默认为double型,申明float型常量,须后加‘f或‘F' 浮点型常量有两种示意模式 十进制数模式:如:5.12 512.0f .512(必须有小数点)迷信计数法模式:如:5.12e2[5.12*10的2次方]5.12E-2[5.12/10的2次方]通常状况下,应该应用double型,因为它比float型更准确。double num9 = 2.1234567851;float num10= 2.1234567851F; 浮点数应用陷阱:2.7和8.1/3比拟 public class FloatDetail { //编写一个main办法 public static void main(String[] args) { //Java 的浮点型常量(具体值)默认为double型,申明float型常量,须后加‘f’或‘F' //float num1 = 1.1; //对不对?谬误 float num2 = 1.1F; //对的 double num3 = 1.1; //对 double num4 = 1.1f; //对 //十进制数模式:如:5.12 512.0f .512 (必须有小数点) double num5 = .123; //等价 0.123 System.out.println(num5); //迷信计数法模式:如:5.12e2 [5.12 * 10的2次方 ] 5.12E-2 [] System.out.println(5.12e2);//512.0 System.out.println(5.12E-2);//0.0512 //通常状况下,应该应用double型,因为它比float型更准确。 //[举例说明]double num9 = 2.1234567851;float num10 = 2.1234567851F; double num9 = 2.1234567851; float num10 = 2.1234567851F; System.out.println(num9); System.out.println(num10); //浮点数应用陷阱: 2.7 和 8.1 / 3 比拟 //看看一段代码 double num11 = 2.7; double num12 = 2.7; //8.1 / 3; //2.7 System.out.println(num11);//2.7 System.out.println(num12);//靠近2.7的一个小数,而不是2.7 //失去一个重要的应用点: 当咱们对运算后果是小数的进行相等判断时,要小心 //应该是以两个数的差值的绝对值,在某个精度范畴类判断 if( num11 == num12) { System.out.println("num11 == num12 相等"); } //正确的写法 , ctrl + / 正文快捷键, 再次输出就勾销正文 if(Math.abs(num11 - num12) < 0.000001 ) { System.out.println("差值十分小,到我的规定精度,认为相等..."); } // 能够通过java API 来看 下一个视频介绍如何应用API System.out.println(Math.abs(num11 - num12)); //细节:如果是间接查问得的的小数或者间接赋值,是能够判断相等 }}当咱们对运算后果是小数的进行相等判断时,要小心应该是以两个数的差值的绝对值,在某个精度范畴类判断。 ...

April 12, 2023 · 2 min · jiezi

关于java:聊聊如何运用JAVA注解处理器APT

什么是APTAPT(Annotation Processing Tool)它是Java编译期注解处理器,它能够让开发人员在编译期对注解进行解决,通过APT能够获取到注解和被注解对象的相干信息,并依据这些信息在编译期按咱们的需要生成java代码模板或者配置文件(比方SPI文件或者spring.fatories)等。APT获取注解及生成代码都是在代码编译时候实现的,相比反射在运行时解决注解大大提高了程序性能 APT的工作流程 什么是注解注:因为APT = 注解+ 注解处理器(AbstractProcessor)。因而须要理解什么是注解,不过对于java开发人员来说,注解应该是耳熟能详了,这边就不再阐述。如果不理解啥是注解的小伙伴,能够查看如下文章科普一下 https://baike.baidu.com/item/%E6%B3%A8%E8%A7%A3/22344968 这边得特地说下元注解@Retention 因为APT是在java编译器应用,因而@Retention的value通常指定为source或者class,这样能够进步一点性能。就我集体而言,我偏向指定为source APT之Element罕用元素以及Element元素罕用变量1、罕用元素这些元素映射到java,我通过一个例子大家应该就能够理解这些元素是指什么 2、Element元素罕用变量更多element具体内容能够查看如下链接 https://www.jianshu.com/p/899063e8452e 创立注解处理器步骤创立注解类创立一个继承自 AbstractProcessor 的类,这就是 APT 的外围类注册处理器创立注解处理器示例注: 示例要实现的性能,通过一个自定义注解AutoComponent,通过注解处理器扫描解析AutoComponent注解,并生成lybgeek.components,spring通过解析lybgeek.components,实现bean注册 1、创立注解类@Documented@Retention(RetentionPolicy.SOURCE)@Target(ElementType.TYPE)public @interface AutoComponent {}2、创立一个继承自 AbstractProcessor 的类这边需介绍这个类外面几个外围的办法 public synchronized void init(ProcessingEnvironment processingEnv)init办法能够让咱们处理器的初始化阶段,通过ProcessingEnvironment来获取一些帮忙咱们来解决注解的工具类 // Element操作类,用来解决Element的工具Elements elementUtils = processingEnv.getElementUtils();// 类信息工具类,用来解决TypeMirror的工具Types typeUtils = processingEnv.getTypeUtils();// 日志工具类,因为在process()中不能抛出一个异样,那会使运行注解处理器的JVM解体。所以Messager提供给注解处理器一个报告谬误、正告以及提示信息的路径,用来写一些信息给应用此注解器的第三方开发者看Messager messager = processingEnv.getMessager();// 文件工具类,罕用来读取或者写资源文件Filer filer = environment.getFiler();public Set<String> getSupportedAnnotationTypes()getSupportedAnnotationTypes办法用来指定须要解决的注解汇合,返回的汇合元素须要是注解全门路(包名+类名) public SourceVersion getSupportedSourceVersion()getSupportedSourceVersion办法用来指定以后正在应用的Java版本,个别返回SourceVersion.latestSupported()示意最新的java版本即可 public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)process是注解处理器外围办法,注解的解决和生成代码或者配置资源都是在这个办法中实现。 Java官网文档给出的注解处理过程的定义:注解处理过程是一个有序的循环过程。在每次循环中,一个处理器可能被要求去解决那些在上一次循环中产生的源文件和类文件中的注解。 每次循环都会调用process办法,process办法提供了两个参数,第一个是咱们申请解决注解类型的汇合(也就是咱们通过重写getSupportedAnnotationTypes办法所指定的注解类型),第二个是无关以后和上一次循环的信息的环境。返回值示意这些注解是否由此 Processor 申明,如果返回 true,则这些注解已申明并且不要求后续 Processor 解决它们;如果返回 false,则这些注解未声明并且可能要求后续 Processor 解决它们。 ...

April 11, 2023 · 1 min · jiezi

关于java:索引优化优化你又是一个好MongoDB博学谷狂野架构师

MongoDB索引优化 作者: 博学谷狂野架构师GitHub:GitHub地址 (有我精心筹备的130本电子书PDF) 只分享干货、不吹水,让咱们一起加油!索引简介索引通常可能极大的进步查问的效率,如果没有索引,MongoDB在读取数据时必须扫描汇合中的每个文件并选取那些合乎查问条件的记录。什么是索引索引最罕用的比喻就是书籍的目录,查问索引就像查问一本书的目录。实质上目录是将书中一小部分内容信息(比方题目)和内容的地位信息(页码)独特形成,而因为信息量小(只有题目),所以咱们能够很快找到咱们想要的信息片段,再依据页码找到相应的内容。同样索引也是只保留某个域的一部分信息(建设了索引的field的信息),以及对应的文档的地位信息。 假如咱们有如下文档(每行的数据在MongoDB中是存在于一个Document当中)姓名id部门cityscore张三2xxxBeijing90李四1xxxShanghai70王五3xxxguangzhou60索引的作用如果咱们想找id为2的document(即张三的记录),如果没有索引,咱们就须要扫描整个数据表,而后找出所有为2的document。当数据表中有大量documents的时候,这个工夫就会十分长(从磁盘上查找数据还波及大量的IO操作)。建设索引后会有什么变动呢?MongoDB会将id数据拿进去建设索引数据,如下 索引值地位1pos22pos13pos3索引的工作原理这样咱们就能够通过扫描这个小表找到document对应的地位。查找过程示意图如下: 索引为什么这么快为什么这样速度会快呢?这次要有几方面的因素索引数据通过B树来存储,从而使得搜寻的工夫复杂度为O(logdN)级别的(d是B树的度, 通常d的值比拟大,比方大于100),比原先O(N)的复杂度大幅降落。这个差距是惊人的,以一个理论例子来看,假如d=100,N=1亿,那么O(logdN) = 8, 而O(N)是1亿。是的,这就是算法的威力。索引自身是在高速缓存当中,相比磁盘IO操作会有大幅的性能晋升。(须要留神的是,有的时候数据量十分大的时候,索引数据也会十分大,当大到超出内存容量的时候,会导致局部索引数据存储在磁盘上,这会导致磁盘IO的开销大幅减少,从而影响性能,所以务必要保障有足够的内存能容下所有的索引数据) 当然,事物总有其两面性,在晋升查问速度的同时,因为要建设索引,所以写入操作时就须要额定的增加索引的操作,这必然会影响写入的性能,所以当有大量写操作而读操作比拟少的时候,且对读操作性能不须要思考的时候,就不适宜建设索引。当然,目前大多数互联网利用都是读操作远大于写操作,因而建设索引很多时候是十分划算和必要的操作。 查看索引索引是进步查问查问效率最无效的伎俩。索引是一种非凡的数据结构,索引以易于遍历的模式存储了数据的局部内容(如:一个特定的字段或一组字段值),索引会按肯定规定对存储值进行排序,而且索引的存储地位在内存中,所在从索引中检索数据会十分快。如果没有索引,MongoDB必须扫描汇合中的每一个文档,这种扫描的效率非常低,尤其是在数据量较大时。 默认主键索引在创立汇合期间,MongoDB 在_id]字段上 创立惟一索引,该索引可避免客户端插入两个具备雷同值的文档。您不能将此索引放在字段上。 查看索引查看汇合索引要返回汇合中所有索引的列表能够应用db.collection.getIndexes()查看现有索引COPYdb.zips.getIndexes();查看zips汇合的所有索引,咱们看到有一个默认的_id_索引,并且是一个升序索引 查看数据库若要列出数据库中所有汇合的所有索引,则需在 MongoDB 的 Shell 客户端中进行以下操作:COPYdb.getCollectionNames().forEach(function(collection){ indexes = db[collection].getIndexes(); print("Indexes for [" + collection + "]:" ); printjson(indexes);});这样能够列出本数据库的所有汇合的索引 索引罕用操作创立索引MongoDB应用 createIndex() 办法来创立索引。留神在 3.0.0 版本前创立索引办法为 db.collection.ensureIndex(),之后的版本应用了 db.collection.createIndex() 办法,ensureIndex() 还能用,但只是 createIndex() 的别名。 语法createIndex()办法根本语法格局如下所示:COPYdb.collection.createIndex(keys, options)语法中 Key 值为你要创立的索引字段,1 为指定按升序创立索引,如果你想按降序来创立索引指定为 -1 即可。COPYdb.zips.createIndex({"pop":1})这样就依据pop字段创立了一个升序索引 索引参数createIndex() 接管可选参数,可选参数列表如下ParameterTypeDescriptionbackgroundBoolean建索引过程会阻塞其它数据库操作,background可指定当前台形式创立索引,即减少 “background” 可选参数。 “background” 默认值为false。uniqueBoolean建设的索引是否惟一。指定为true创立惟一索引。默认值为false.namestring索引的名称。如果未指定,MongoDB的通过连贯索引的字段名和排序程序生成一个索引名称。dropDupsBoolean3.0+版本已废除。在建设惟一索引时是否删除重复记录,指定 true 创立惟一索引。默认值为 false.sparseBoolean对文档中不存在的字段数据不启用索引;这个参数须要特地留神,如果设置为true的话,在索引字段中不会查问出不蕴含对应字段的文档.。默认值为 false.expireAfterSecondsinteger指定一个以秒为单位的数值,实现 TTL设定,设定汇合的生存工夫。vindex version索引的版本号。默认的索引版本取决于mongod创立索引时运行的版本。weightsdocument索引权重值,数值在 1 到 99,999 之间,示意该索引绝对于其余索引字段的得分权重。default_languagestring对于文本索引,该参数决定了停用词及词干和词器的规定的列表。 默认为英语language_overridestring对于文本索引,该参数指定了蕴含在文档中的字段名,语言笼罩默认的language,默认值为 language.示例创立一个名称是pop_union_index的索引,依照pop字段降序,并且在10秒后删除COPYdb.zips.createIndex( { "pop":-1 }, { "name":"pop_union_index", "expireAfterSeconds":10 })这样咱们就创立了一个索引 ...

April 11, 2023 · 4 min · jiezi

关于java:线上问题排查异闻录

如何解决堆内存溢出问题OOM有很多种状况啊,这里就先解说最常见也是最容易观测的java.lang.OutOfMemoryError: Java heap space,也就是堆内存溢出。 发现启动Java程序的时候,最好参数加上-XX:+HeapDumpOnOutOfMemoryError,该参数不影响程序运行,运行时没有任何开销,只有OOM时会主动生成Java Heap Dump(特定时刻 JVM 内存中所有对象的快照)。该文件默认会在运行应用程序同级目录下生成一个格局为hprof的文件,当然也能够应用参数-XX:HeapDumpPath=/data指定生成到data文件夹下。 这里说一下我对于Java程序运行增加参数的一些了解,这是我我的项目的一个惯例启动命令,java -javaagent:/usr/local/app/skywalking_agent_zy/skywalking-agent.jar -Dskywalking.agent.service_name=appName−Dskywalking.collector.backendservice={appName} -Dskywalking.collector.backend_service=appName−Dskywalking.collector.backendservice={skywalkingIp}:skywalkingPort−Dskywalking.plugin.toolkit.log.grpc.reporter.serverhost={skywalkingPort} -Dskywalking.plugin.toolkit.log.grpc.reporter.server_host=skywalkingPort−Dskywalking.plugin.toolkit.log.grpc.reporter.serverhost={skywalkingIp} jvmoption−Dserver.port=8080−Denv=jvmoption -Dserver.port=8080 -Denv=jvmoption−Dserver.port=8080−Denv={env} -jar /usr/local/app/app.jar。${}占位符这里是在DevOps下面配的,当然大家也没必要关注,嘻嘻。这里这个env是公司框架让配的环境参数,后面Javaagent一堆参数都是skywalking要用的。 除开这些客制化的货色,对于一般的利用,个别配置堆大小雷同比拟好,因为通常来说一个服务器或者容器只会有一个Java利用,开释内存给谁用呢,是吧,没那必要。JVM初始调配的堆内存由-Xms指定,默认是物理内存的1/64,JVM最大调配的堆内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限度,空余堆内存大于70%时,JVM会缩小堆直到-Xms的最小限度。因而个别设置-Xms、-Xmx相等以防止在每次GC后调整堆的大小。 定位拿到hprof文件后,能够选用jvisualvm(Jdk8之后不自带,须要到Github上下载)、JProfiler和IDEA的Profiler(旗舰版才有)关上文件,三者的操作逻辑都是相似的,目前我用的最舒服的是JProfiler,以下就拿JProfiler截图举例。 导入hprof文件到JProfiler之后通过解析,默认会跳到该界面,这里间接选下面的最大对象,持续解析。 这里右键选定比拟大的对象后会弹出这样一个框,抉择援用-传入援用。为啥是传入援用呢,因为咱们要找问题的源头啊,哪里来的才是比拟重要的。 找到对应堆栈信息,点击显示更多,即可发现带善人。 以上就是一次残缺的查问过程,如果点开发现都是差不多的内容,为了少点几次,爱护鼠标,我倡议能够换成夕阳图更加便捷地查看 能够察看到绝对类型地这个对象比拟多啊,这里点击一下这块进入外部查问 如何解决CPU占用高问题CPU占用高的问题就没有挂了之后主动dump文件的坏事了。这时候须要善用jstack、监控和Arthas等工具。 发现失常来说,咱们会有监控软件去监控服务器的一些性能指标,我这用的是Prometheus+Grafana,十分公众哈。 如图能够察看到一个服务器CPU占用的折线图,配合告警能够及时告诉相干人员定位问题。 定位-传统武学通过下面地监控及时发现问题,接下来就该上手具体的操作了。 top -o %CPU,Linux上按CPU从大到小排序,找到占用最多的PID(这里假如是Java利用)jstack pid > thread.txt,通过jstack命令打印以后Java利用的堆栈信息top -Hp pid,通过该命令察看此pid过程中所有线程的CPU占用找到线程pid,通过命令printf '%x\n' pid失去转换为16进制的nid在jstack取得的文件thread.txt中,找到nid对应的线程堆栈信息,找到对应代码块即可通常除了CPU占用过高的线程,还须要重点关注线程状态为BLOCKED、WAITING和TIMED_WAITING的局部定位-新派宝典我一开始接触的也是传统武学,啪啪啪一堆命令敲得也是十分麻烦嗷,那有没有开箱即用的好货色呢。没错,那必定是有的,就是赫赫有名的Arthas啦。 下载Arthas.jar,curl -O arthas.aliyun.com/arthas-boot…运行java -jar arthas-boot.jar并抉择须要监听的Java利用,图形化很赞输出命令dashboard关上看板,随时监控,默认5000ms一刷针对下面CPU问题,间接抉择Thread系列命令成果如下,牛中牛中牛,解放双手。相比jstack输入的文件,甚至多了cpuUsage这个参数,更加直观。 Arthas还有很多别的牛逼性能,不仅仅是Jdk工具的一个打包,更是对前者进行了易用性上的极大优化,同时也提供了很多新性能,要晓得这玩意才一百多KB啊。

April 11, 2023 · 1 min · jiezi

关于java:Java静态代码块和静态类静态导入

前言在上一篇文章中给大家解说了 static动态关键字,以及动态变量、动态常量和静态方法等内容。 然而对于static,还有其余的一些内容,比方动态类、动态代码块和动态导入等,接下来给大家持续剖析解说。咱们一起来看看这些内容都是怎么用吧。 全文大概 【3300】字 ,不说废话,只讲能够让你学到技术、明确原理的纯干货!本文带有丰盛的案例及配图,能够让你更好地了解和使用文中的技术概念,并能够给你带来具备足够启迪的思考 一. 动态代码块 概念由static润饰的代码块称为动态代码块,每个类中能够有多个动态代码块,每个动态代码块都只会在类加载时执行一次。对那些只须要进行一次操作的初始化代码,就能够放在动态代码块中执行。动态代码块具备如下个性:● 动态代码块相似于是一个办法,但它不能够在办法中调用,也不能存在于任何办法体中; ● 动态代码块能够写在类中的任何中央,一个类中也能够有多个动态代码块; ● 动态代码块在类加载时执行; ● 动态代码块优先于动静代码块执行; ● 如果类中蕴含多个动态代码块,则JVM虚构机会按它们在类中呈现的先后顺序顺次执行,每个动态代码块只会被执行一次; ● 动态代码块与静态方法一样,不能间接拜访类的实例变量和实例办法,须要通过类的实例对象来拜访。 语法动态代码块的语法格局如下:static { //代码内容 } 动态代码块的语法格局比拟奇异,static关键字前面间接跟一个{ }花括号,这就是动态代码块。咱们能够在这个动态代码中编写若干代码,成果相似于是一个办法。 案例3.1 定义User类咱们先来定义一个User类,在该类中定义一个动态代码块,一个非动态代码块,还有一个构造方法。在Java中,依照代码执行工夫的早晚:动态代码块 > 非动态代码块 > 构造方法 > 一般办法 咱们要记住以下几点: ● 动态代码块,在类被加载时就会主动调用,且只会被调用一次。 ● 非动态代码块,在对象被创立时主动调用,每次创建对象时都会执行。 ● 而构造方法,每创立一个对象就会执行一次。 public class User { //动态属性,属于整个类,被整个类的所有对象共享! static int num = 10; //一般属性,属于某个对象,是对象公有的! private int age=20; //动态代码块,在类被加载时主动调用,且只会被调用一次。比一般代码块先执行! static { //无论创立几个User对象,本动态代码块都只会执行一次,num++变成11 System.out.println("这是动态代码块,num="+(num++)); } //非动态代码块,在对象被创立时主动调用,每次创建对象时都会执行,比构造方法先执行! { //每创立一个User对象,就会执行一次本代码块,num++变成12,age=20. System.out.println("这是非动态代码块,num="+(num++)+",age="+(age++)); } //构造方法 public User(){ //每创立一个User对象,就会执行一次构造方法,num++变成13,age=21. System.out.println("这是无参构造方法,num"+(num++)+",age="+(age++)); } } 3.2 定义测试类接下来咱们再定义一个测试类,在这里创立3个User对象。 public class UserTest { public static void main(String[] args) { ...

April 11, 2023 · 2 min · jiezi

关于java:Java概述与基础知识

文章和代码曾经归档至【Github仓库:https://github.com/timerring/java-tutorial 】或者公众号【AIShareLab】回复 java 也可获取。Java 历史1990 sun公司启动绿色打算1992创立oak(橡树)语言->java1994 gosling加入硅谷大会演示java性能震惊世界。1995 sun 正式公布java第1个版本。2009年,甲骨文公司发表收买Sun 。2011,公布java7 Java技术体系平台Java SE (Java Standard Edition) 标准版反对面向桌面级利用(如Windows下的应用程序)的Java平台,提供了残缺的Java外围API,此版本以前称为J2SEJava EE(Java Enterprise Edition)企业版是为开发企业环境下的应用程序提供的一套解决方案。该技术体系中蕴含的技术如:Servlet、Jsp等,次要针对于Web利用程序开发。版本以前称为J2EEJava ME(Java Micro Edition)小型版反对Java程序运行在挪动终端(手机、PDA)上的平台,对Java API有所精简,并退出了键对挪动终端的反对,此版本以前称为J2MEJava 重要特点Java 语言是面向对象的(oop)Java 语言是强壮的。Java 的强类型机制、异样解决、垃圾的主动收集等是Java 程序健壮性的重要保障Java 语言是跨平台性的。[编译好的.class 文件能够在多个零碎下运行,这种个性称为跨平台]Java 语言是解释型的 解释性语言:javascript,PHP, java 编译性语言: c / c++ 区别是:解释性语言,编译后的代码,不能间接被机器执行,须要解释器来执行, 编译性语言, 编译后的代码, 能够间接被机器执行。 Java 虚拟机[JVM]JVM 是一个虚构的计算机,具备指令集并应用不同的存储区域。负责执行指令,治理数据、内存、寄存器,蕴含在JDK 中。对于不同的平台,有不同的虚拟机。Java 虚拟机机制屏蔽了底层运行平台的差异,实现了“一次编译,到处运行”。 JDK,JREJDK 根本介绍JDK 的全称(Java Development Kit Java 开发工具包) JDK = JRE + java 的开发工具[java, javac,javadoc,javap 等]JDK 是提供给Java 开发人员应用的,其中蕴含了java 的开发工具,也包含了JRE。JRE 根本介绍JRE(Java Runtime Environment Java 运行环境) JRE = JVM + Java 的外围类库[类]包含Java 虚拟机(JVM Java Virtual Machine)和Java 程序所需的外围类库等,如果想要运行一个开发好的Java 程序,计算机中只须要装置JRE 即可。JDK、JRE 和JVM 的蕴含关系JDK = JRE + 开发工具集(例如Javac,java 编译工具等)JRE = JVM + Java SE 规范类库(java 外围类库)如果只想运行开发好的.class 文件只须要JREJava 疾速入门开发步骤 ...

April 11, 2023 · 2 min · jiezi

关于java:一文吃透Arthas常用命令

Arthas 常用命令简介Arthas 是Alibaba开源的Java诊断工具,动静跟踪Java代码;实时监控JVM状态,能够在不中断程序执行的状况下轻松实现JVM相干问题排查工作 。反对JDK 6+,反对Linux/Mac/Windows。这个工具真的很好用,而且入门超简略,非常举荐。 应用场景这个类从哪个 jar 包加载的?为什么会报各种类相干的 Exception?我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?遇到问题无奈在线上 debug,难道只能通过加日志再从新公布吗?线上遇到某个用户的数据处理有问题,但线上同样无奈 debug,线下无奈重现!是否有一个全局视角来查看零碎的运行状况?有什么方法能够监控到JVM的实时运行状态?接下来,围绕这6个问题,学习下Arthas的根本用法。本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址 如果拜访不了Github,能够拜访gitee地址。 gitee地址 装置执行上面命令下载 wget https://alibaba.github.io/arthas/arthas-boot.jar用java -jar的形式启动 java -jar arthas-boot.jar[INFO] Found existing java process, please choose one and hit RETURN.* [1]: 79952 cn.test.MobileApplication [2]: 93872 org.jetbrains.jps.cmdline.Launcher而后输出数字,抉择你想要监听的利用,回车即可 常用命令查问arthas版本 [arthas@79952]$ version3.1.41、stack输入以后办法被调用的调用门路 很多时候咱们都晓得一个办法被执行,然而有很多中央调用了它,你并不知道是谁调用了它,此时你须要的是 stack 命令。 参数名称参数阐明class-pattern类名表达式匹配method-pattern办法名表达式匹配[arthas@79952]$ stack com.baomidou.mybatisplus.extension.service.IService getOnePress Q or Ctrl+C to abort.Affect(class-cnt:202 , method-cnt:209) cost in 10761 ms.ts=2019-11-13 11:49:13;thread_name=http-nio-8801-exec-6;id=2d;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@a6c54c3 @com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne() at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:230) ...... ...... at cn.test.mobile.controller.order.OrderController.getOrderInfo(OrderController.java:500)能够看到OrderController.java的第500行调用了这个getOne接口。 留神这个命令须要调用后才会触发日志,类似的还有watch、trace等 最全面的Java面试网站2、jad反编译指定已加载类的源码 ...

April 11, 2023 · 4 min · jiezi

关于java:图灵JAVA互联网架构师五期道狭草木长夕露沾我衣

download:图灵JAVA互联网架构师五期Java是一种风行的编程语言,用于开发各种应用程序。自从1995年推出以来,Java曾经成为最风行的编程语言之一,被宽泛用于开发企业级应用程序、挪动应用程序、游戏、嵌入式零碎和Web应用程序等。在本文中,咱们将深入探讨Java的一些基本知识和利用。 1.根本语法 Java的语法结构与C++相似,但更加简略和易于学习。Java语言具备面向对象的个性,反对继承、封装和多态等概念。在Java中,你须要理解变量、数据类型、条件语句、循环语句、数组、函数、类、对象等基本概念。 2.利用程序开发 Java可用于开发各种应用程序,包含桌面应用程序、Web应用程序和挪动应用程序。在Java桌面利用程序开发中,你能够应用Java Swing或JavaFX来创立用户界面,并应用Java API进行数据库操作和其余工作。在Web利用程序开发中,你能够应用Java Servlet、JavaServer Pages(JSP)、Spring等框架来创立动静Web应用程序。在挪动利用程序开发中,你能够应用Java和Android SDK来开发Android应用程序。 3.工具和框架 在Java开发中,有许多工具和框架能够帮忙你进步开发效率。Eclipse、NetBeans和IntelliJ IDEA是风行的Java集成开发环境(IDE),提供了代码编辑、调试和部署等性能。Maven和Gradle是罕用的构建工具,能够帮忙你治理依赖关系和构建Java应用程序。Spring和Hibernate等框架提供了许多性能和库,能够帮忙你疾速开发Java应用程序。 4.性能优化 在Java开发中,性能优化是一个十分重要的问题。你应该晓得如何编写高效的Java代码,如何优化内存应用和垃圾回收,如何优化算法和数据结构。你能够应用Java虚拟机(JVM)提供的工具来剖析和优化Java应用程序的性能,例如jstat、jconsole、jvisualvm等。 5.并发编程 Java提供了许多性能和库,能够帮忙你进行并发编程。Java中的线程机制使你能够轻松地创立多线程程序。Java中的锁、信号量和同步块等机制能够帮忙你管制并发访问共享资源。Java 8中引入的Stream API能够帮忙你进行函数式编程和并行处理。 总之,Java是一种风行的编程语言,被宽泛用于开发各种应用程序。在Java开发

April 10, 2023 · 1 min · jiezi

关于java:Java到底是什么

既然各位小伙伴当初曾经决定要学习Java了,那首先得对Java有根本的理解吧,所以接下来先用一篇文章,来给大家介绍一下Java到底是个啥。 情谊提醒:大家要记住,无论咱们学习任何技术,都要晓得这个技术是什么、干嘛的、怎么用、为什么这么用,以及应用时呈现了问题该怎么解决! 一. Java简介 起源既然各位打算当前要靠Java来养家糊口了,那对Java的理解是不是应该更多一些呢?比方Java这个技术是怎么产生的?接下来给大家讲个小故事,让咱们一起来看看Java的起源吧。20世纪90年代,经济高速倒退,大家有钱了就想谋求更高的生活品质。 过后创造了很多稀奇古怪的电子产品,比方有钱人必备的“大哥大”、BB机、电视机顶盒、烤箱等。咱们晓得,硬件产品必须要有软件系统进行撑持能力运行,就好比人必须有灵魂能力称之为人。所以过后为了配合硬件的倒退,研发出了驰名的单片机零碎,这就大幅晋升了电子产品的智能化水平。过后有一个叫做“Sun”(不是Son哦)的公司,眼光很敏锐。 为了抢占宽广的生产电子产品市场,在1991年成立了一个名为“Green”的项目组,由詹姆斯·高斯林(高司令)、帕特里克等几个工程师一起负责研发新技术,专攻家电产品里的嵌入式应用开发。一开始Green项目组打算用C++进行嵌入式开发,但因为C++写进去的程序特地简单和宏大,不适宜在嵌入式的环境中运行。而且不同厂家生产的电子产品,其底层所应用的硬件零碎也各有不同,C++写进去的货色无奈实现“一次编码,处处运行”的跨平台需要。 所以为了解决以上这些问题,Green项目组依据嵌入式的特点,对C++进行了革新,去除了C++中不太实用及影响平安的局部,并针对实时性要求,开发出一种称为Oak(橡树)的面向对象语言。但此时Oak除了比C++更简略之外,其实也没有太大的区别,所以过后的硬件厂商对Oak没有太大的激情。 而Oak也就因为不足硬件的反对无奈进入市场,从而被搁置了下来。到了1994年6、7月间,Green团队决定扭转接下来的倒退指标。因为Oak自身是一种精简的语言,程序十分小,很适宜在网络上传输,所以他们决定把Oak用在万维网上。 到了1995年,Sun公司正式决定启用Oak,并推出了能够伴随网页在网络上传输的Applet技术。后果就在此时,Sun公司发现Oak这个商标被别的公司给提前抢注了。所以没方法,只能将Oak从新改名!大家都晓得,取名字是一个很令人抓狂的事,大家一时都找不到适合的名字来重新命名。在“百思不得其解”之际,过后正在喝82年爪哇岛咖啡的詹姆斯·高斯林眉头一皱;计上心来,罗唆就把Oak改名叫“Java”得了。 于是,从此Oak更名为Java,所以高斯林也就成了公认的“Java他爹”!幸好高斯林过后不是在蹲坑,要不然,em.......到了1996年1月,Sun公司公布了Java的第一个开发工具包 (JDK 1.0) ,这也是Java倒退历程中的重要里程碑,标记着Java真正成为了一种独立的开发工具。以上就是Java语言的起源由来,当初你对它的历史晓得了吗? 概念(把握)通过下面的介绍,置信各位曾经对Java有所理解了,但实际上Java到底是个什么鬼,有些敌人可能还是没有搞清楚。别急,再给大家把Java的外围概念提炼一下。 Java是已经赫赫有名的Sun公司,在1995年5月正式推出的一种面向对象的程序设计语言。Java一开始是Sun公司的产品,但起初Sun被Oracle(甲骨文)给收买了,所以当初Java属于Oracle公司。Java语言是由James Gosling(詹姆斯·高斯林,“高司令” )和共事们独特研发的,通常咱们认为高斯林是“Java之父”。Java是一种介于编译型和解释型之间的编程语言,但更偏差于解释型。 编译型语言写出的代码会依据CPU类型的不同,编译成不同的机器码执行,工作原理相似于“翻译书籍”,如C、C++等;解释型语言能够由解释器间接加载源码运行,工作原理相似于“同声传译”,但运行效率较低,如JavaScript、Python、Ruby等。为了使得定位更清晰,Sun公司将Java分成了三个技术体系:JavaSE(J2SE) :Java 2 Platform Standard Edition,Java平台标准版,蕴含规范的JVM和规范库;JavaEE(J2EE) :Java 2 Platform,Enterprise Edition,Java平台企业版,在JavaSE的根底上减少了大量的API和库,用于企业级我的项目开发;JavaME(J2ME) :Java 2 Platform Micro Edition,Java平台微型版,次要针对挪动平台开发。 2005年6月,JavaOne大会召开,公布Java SE 6版本,并正式将Java版本名称中的数字“2”勾销。从此J2EE更名为Java EE,J2SE更名为Java SE,J2ME更名为 Java ME。 所以如果有谁再跟你说什么“J2SE、J2EE、J2ME”,你就送他一个黑人问号脸,“你到底是有多out才会说出这么老古董的话”? 技术体系尽管在下面的大节中曾经给大家说过,Sun把Java分成了JavaSE、JavaEE、JavaME共3个平台体系,但我还是想把这个知识点再跟大家强调一下,因为有太多的小白已经问过我:我到底是要学JavaSE,还是JavaEE?JavaSE和JavaEE到底是什么关系?.......“所以在咱们正式开始学习Java之前,还是心愿可能把各位心中的这些纳闷都给你解决掉。 为了搞清楚JavaSE、JavaEE、JavaME之间的关系,给大家绘制了上面这张图片 从上图中你应该能够看进去,JavaEE的“范畴是最大的“,这示意什么意思呢?这其实次要是说,JavaEE这个分类里蕴含的API(利用程序接口,咱们能够临时了解为Java提供的各种”工具“)最多,而JavaSE则齐全蕴含在JavaEE外面,JavaME中有一小部分的API和JavaSE是重合的。 由此咱们能够得出一个论断,作为初学者,咱们须要先学习JavaSE里提供的各种罕用API,等把JavaSE学完了就有”资格“去学习JavaEE或JavaME了!也就是说,JavaSE是Java的必备入门根底,初学者必定要先学习JavaSE。这就好比你要学习西医技术,有针灸、推拿、中药等几个方向能够供你抉择。但无论你要抉择哪个方向,你都得先学习《西医基础理论》这门课,学完了这个能力有资格去学习其余具体的某个方向。 当初你晓得JavaSE与JavaEE的关系了吗?但有的小伙伴还会好奇,要不要学习JavaME呢?通知你,这个就算了!JavaME原本是Sun用于开发手机等设施的技术平台,但起初Android、iOS的异军突起,当初简直就没人应用JavaME了,所以大家晓得有这么一个货色就能够了。咱们学习完JavaSE之后,还不具备企业级开发的能力,接下来要学习JavaEE里的各种API。所以咱们学习Java的正确路线,就是先学JavaSE,再学JavaEE,而的《从零开始学Java》系列文章,次要就是解说JavaSE哦!其实对于初学者来说,你大可不必过于纠结这些没什么实用价值的概念。等学到前面,你自然而然就会明确它们之间的具体区别,咱们只需对其有个大抵的理解,把精力放在最外围的问题上即可。 Java个性对于Java,咱们还须要理解一下Java的一些劣势和个性,有时候面试官会贱兮兮的问你:你对Java理解多少?你为什么学习Java而不是其余语言?Java有哪些劣势......针对这样的问题,咱们就简略答复一下Java的外围个性即可。应用简略: Java的语法与C和C++很靠近,能够不便大量C系程序员疾速转向Java。但又抛弃了C++中那些特地简单难用的个性,如操作符重载、多继承、主动强制类型转换等。 另外Java不反对指针,而是反对援用,并提供了主动调配和GC垃圾回收机制,程序员不用关怀内存治理。面向对象: Java提供了类、接口和单继承等面向对象的个性,并反对类与接口之间的实现机制,全面反对动静绑定。能够说,Java语言是第一个十分纯正的面向对象的程序设计语言。强壮平安: Java具备强类型机制、异样解决、GC垃圾主动收集、安全检查机制、抛弃指针等个性,保障了Java程序的健壮性。并且Java提供了平安机制来避免恶意代码的攻打,能够通过ClassLoader加载器进行字节代码查看,通过SecurityManager平安管理机制设置平安哨兵,保障了Java程序的安全性。 跨平台/可移植性: Java基于JVM虚拟机机制,.java文件会被JVM编译成适宜不同平台的.class字节码文件,实现了”一次编写,处处运行“的跨平台个性。正因为这个个性,也使得Java代码能够轻松实现不同平台间的移植。开源/收费:在2006年的JavaOne大会上,Sun公司发表要将Java开源,之后陆续将JDK的各个局部在GPL v2(GNU General Public License v2)协定下公开了源码(即OpenJDK)。除了极少量的产权代码外,OpenJDK简直包含了Sun JDK的全副代码,两者的代码基本上齐全一样。目前JDK 8及以前的版本都是完全免费的,JDK 9之后Oracle发表会对企业进行免费,然而企业能够收费应用Open JDK。高性能: Java是介于编译型与解释型之间的语言,但更偏差于解释型,执行性能比C语言更高效。而且当初Java的编译器不断更新,性能曾经与C++相似了。 反对网络和多线程: Java反对 Internet网络开发,提供了用于网络编程的类库,比方URL、URLConnection、Socket、ServerSocket、RMI(近程办法激活)等,并且反对多线程和并发同步机制。二. Java发展史对一个行将开始学习Java的小白来说,咱们还是有必要适当地理解一下Java的发展史的,看看这些年Java都经验了哪些历史改革吧。1995年5月23日,Java诞生;1996年1月,JDK 1.0诞生;1997年4月2日,Java One会议召开,参与者超过万人,突破过后寰球同类会议规模纪录;1997年9月,Java Developer Connection社区成员超十万人;1998年2月,JDK 1.1被下载超过 2,000,000次;1998年12月8日,JAVA2企业平台J2EE公布;1999年6月,SUN公布Java的三个版本:JavaSE、JavaEE、JavaME;2000年5月8日,JDK 1.3公布;2000年5月29日,JDK 1.4公布;2001年6月5日,NOKIA发表到2003年将会发售超 1亿部反对Java的手机;2002年2月26日,J2SE 1.4公布,Java计算能力有了大幅晋升;2004年9月30日,J2SE 1.5公布,成为Java语言发展史上的又一里程碑。为了示意该版本的重要性,J2SE 1.5更名为 Java SE 5.0;2005年6月,Java One大会召开,Sun公司公布Java SE 6。此时Java各种版本曾经全副更名,勾销了其中的数字 "2":J2EE更名为Java EE,J2SE更名为Java SE,J2ME更名为 Java ME;2006年12月,Sun公司公布JRE 6.0;2009 年04月20日,甲骨文以74亿美元收买Sun,获得了Java版权;2011年7月28日,Oracle公布Java 7.0 正式版;2014年3月18日,Oracle公布Java SE 8.0(目前最支流版本);2017年9月21日,Oracle公布Java SE 9.0;2018年3月21日,Oracle公布Java SE 10.0;2018年9月25日,Oracle公布Java SE 11;2019年3月20日,Oracle公布Java SE 12;2019年9月,Oracle公布Java SE 13;2020年3月,Oracle公布Java SE 14;2020年9月,Oracle公布Java SE 14;2021年3月,Oracle公布Java SE 16;2021年9月, Oracle公布Java SE 17 ;2022年3月,Oracle公布Java SE 18;2022年9月,Oracle公布Java SE 19;......Java持续在大步后退......当然,对于以上历史,大家理解即可,不必去记这些货色。三. Java版本(重点)在下面的章节介绍中,给大家提到了Java的很多版本,并且这些不同的版本所具备的性能也不尽相同。所以就有小白来问了,咱们学习Java时到底该抉择哪个版本呢?是越新越好吗?认为很有必要就这个问题给大家解释一下。在Java的倒退过程中,有很多不同的表述形式,有时候会给初学者造成一些误会。但请你记住,所谓的Java版本,其实就是指JDK的版本,两者是一回事!1. JDK版本Oracle把JDK分成了两种保护状况,即短期反对版本和长期反对版本, 咱们先来看 ...

April 10, 2023 · 1 min · jiezi

关于java:程序员为什么要学Java

全文大概 【 4000】 字,不说废话,只讲能够让你学到技术、明确原理的纯干货!文章带有丰盛案例及配图、视频,只为让你更好的了解和使用文中的技术概念,给你带来具备足够启迪的教程...... ------------------------------前戏已做完,精彩即开始-------------------------- 在正式开始本系列教程之前,心愿先用一篇文章,来扫清你学习前的认知障碍。请动摇本人的学习信念,不要大功告成浪费时间,壹哥心愿各位要么就不学,要么就学会!!! 一. 程序员那点事儿 咱们晓得,每年都会有各种各样不同行业的薪酬排行榜,就比方上面这张图: 如果你用心搜寻过近20年不同行业的薪资排行榜,你就会发现,IT行业的薪酬排名在这20年间简直都是在前3名之内!所以这也就导致了国内简直每一所大中专院校都开设了计算机相关业余,但计算机尤其是软件编程的人才缺口仍然很大,从而推动软件行业的薪资仍然屡翻新高。而随着将来社会的进一步倒退和智能化的遍及,更是须要大量的软件我的项目来满足人类的智能化和便捷化需要。试问,这些大量的软件我的项目由谁来开发? 毫无疑问!那就是程序员呗!正是这些程序员通过编程实现了咱们日常生活中见到的各种软件我的项目,丰盛和便当了咱们的生存,所以请大家为这些程序员们点个赞呗。另外IT行业其实是一个大的行业分类,外面不止是程序员一个岗位,还包含产品、测试、运维、设计、推广等各种类型的职位,但无疑程序员是其中最外围的岗位! so,既然你想投身IT行业,为什么不去从事最外围的岗位呢?在下面说过,尽管当初每年都有大量的计算机专业毕业生,但仍然无奈齐全满足市场的缺口,这就给了其余业余的人员进入IT行业的机会。所以,如果你不是计算机专业毕业的,甚至连大学都没上过,那么能不能做程序员呢?能够十分必定的用一个字来通知你,相对能!!! 有的小伙伴可能会很好奇,那如果想成为程序员该怎么办呢?没别的路径,想成为程序员的前提是你得会编程、懂编程!不会怎么办?学呗!能够在大学里抉择计算机专业,购买编程书籍,或者间接在网上搜各种收费的编程视频、博客等,总之学习材料十分多! IT行业很凋谢,也很偏心!只有你想进,就能够进入;只有你致力付出,就能够失去对得起本人的回报!壹哥其实不想给大家熬鸡汤,只是见过太多大功告成的人。他们艳羡程序员的高薪,灰溜溜地开始学习编程,后果学了几天几个月就放弃了,节约本人的工夫和精力。所以心愿有志于成为程序员的敌人,要么当初就开始,要么就别开始! 二. 编程到底咋回事在下面的章节中,给大家屡次提到了【编程】的概念。 那么对于行业小白来说,【编程】到底是咋回事呢?还是有必要先给糊涂的你解释一下。所谓的编程,其实就是编写程序的简称!也就是利用计算机的代码来解决某个问题,对某个计算体系规定肯定的运算形式,使计算体系依照该计算形式运行,并最终失去相应后果的过程。 小白:说人话行不行?壹哥:好的,安顿!其实咱们大家不必把“编程”想的那么神秘,你齐全能够把“编程”了解成农民工盖房子。 首先有个房地产老板,他想开发一个小区。但他并不会想干立马就干,必须通过很谨慎的大量的后期调研、考查,盖好的这个小区是否合规非法,能不能卖出去,能不能赚钱,这是我的项目的可行性前提条件。可行性确定之后,房地产老板会进行需要剖析。自 己到底想要盖进去一个什么样的小区,是别墅区还是高端小区,还是保障房?老板会有一个本人的需要指标。根本的需要确定了之后,接着老板会找业余的设计师进行房屋设计和布局,整个小区的下水道、绿化、楼栋、户型、车位、格调等都交给这些业余的设计师去设计。 设计的过程中,设计师要一直的请示老板看看是否合乎老板的要求,合格就完事,不合格再批改,一直重复。等到把设计实现,老板就会找施工队,施工人员进场施工。其实咱们这些程序员,就相当于是这些具体的施工人员,依照设计图纸把房子盖进去就好了。 咱们的编码过程,其实就和这个步骤很相似!在盖房的过程中,会有监理人员对房子的品质进行查看,合格的就下一步,不合格就推倒重建或批改。直到最初房子验收合格,老板确认,房子交付给用户应用。 三. 为什么要学Java明确了“编程”的含意之后,可能有不少敌人曾经蠢蠢欲动了,感觉编程也不过如此,那还等什么,连忙搞起来吧。但在各位真正地学习编程技术之前,你肯定要搞清楚一件事,你具体要学习哪一门“编程技术”?啥?难道“编程”技术还分很多种吗?! 是的哦!还是农民工盖房子,尽管大家都是盖房子的,但其实有的人善于盖民宅,有的人善于盖工厂的烟筒,有的人善于盖厂房,也就是说大家的专长是有偏重的!在编程畛域也是这样。目前有各种不同的编程技术,比方Java、Python、Android、iOS、Go、C、C#、C++、H5、Defi等几百种编程语言。 so,在这些泛滥的编程语言中,咱们该学习哪个呢?首先要通知大家,其实咱们无论学习哪种语言都能够,只有你能学的精通,就怕你啥都晓得一点,但啥都没学好!好比咱们玩枪,有汉阳造、三八大盖、莫辛纳甘、盒子炮、M16、AK47、81杠......对一个顶级狙击手来说,他用哪个枪都能对敌人造成微小的挫伤;而对一个菜鸡来说,你给他一把大狙,他也未必有人家用老套筒杀的敌人多。所以,至于你想抉择应用哪把枪,其实你能够依照本人的趣味来。有的人就喜爱高科技新枪,有的人就喜爱复旧格调玩古董。 但实际上这些不同的枪之间,也的确存在很大的差别!在两个人程度相当的状况下,AK47相对能够稳稳地压抑汉阳造!所以,排除了集体的爱好之后,壹哥给大家的倡议就是,你肯定要抉择一把最牢靠的“枪”!留神,这里说是“最牢靠”,而不是说"最新"!最新的货色未必就是牢靠的,实际上当初每年都会研发出很多新枪,但没过几年就都淘汰了,因为这些“枪”没有通过大量的实战测验,无奈胜任实在的“战场需要”。 对于咱们编程技术来说,更是如此!咱们小白抉择任何一个编程语言,肯定不要去抉择最新的技术!有的小白不懂编程畛域的倒退法则,听他人说最近XXX技术挺火,而后就头脑一热去学了。后果用了几个月甚至一年多的工夫学完之后,这个技术凉了,你这不是节约本人的工夫吗?咱们哪有那么多的试错老本!作为一个从业十几年的行业老兵,倡议大家抉择Java作为本人的第一个编程语言! Java从1995年正式公布以来,面世将近30年来,与各种语言PK简直都是稳居前三,最近15年间更是霸榜各编程语言排行榜龙头。通过这么多年的实际考验,具备行业内人尽皆知的劣势:最成熟、企业开发首选、开发者最多、世界排名第一、始终蝉联TIOBE编程语言排行榜前三列。而且Java利用遍布寰球各个行业、各个领域,你所晓得的90%的软件都是Java开发的,比方:驰名的12306电子商务网站——阿里、淘宝、天猫 、京东.....绝大多数电信行业的各种零碎,中国移动、中国联通、中国电信......各个银行零碎、金融零碎、交易系统.....互联网我的项目证券行业零碎游戏后端服务器利用.......Java广泛应用在金融、保险、电商、物流、通信、交通、互联网等各个行业中!能够说,不论是哪个行业,哪个公司,只有他们的我的项目有后端,90%以上都是Java!所以,这么牛逼的编程语言,是不是足以动摇你学习上来的信念了? 更重要的是,Java并不是抱残守缺变化无穷,当初Oracle公司对Java每隔半年就进行一次大的版本更新。即便是这么优良的编程语言都还在一直地进行自我更新,你还有什么理由不更新本人的常识储备呢?放眼当今各种编程语言,唯有Java,能够同时满足如下条件:领有雄厚的历史积淀,海量的我的项目测验,一直的更新迭代,残缺的生态撑持,最宽泛的就业机会。咱们学习编程技术,其实更多的还是从待业的角度来思考!对小白来说,咱们不要去追最新最火的技术。那些技术能活几年都不肯定,3年后让你就业好受不好受? 比方一度十分火爆的iOS,你当初去招聘网站上搜一下iOS的招聘需要,看看还有多少。咱们也不要玩变化无穷的老古董,比方C语言,尽管很多中央都在用,但薪资待遇对小白来说并不敌对。然而Java既有深厚的技术积淀,又在一直地更新以适应市场需求,并且领有残缺的生态链条,你齐全不必放心学习Java后会就业。 所以从待业的角度来看,学习Java作为本人的第一编程语言无疑是最好的抉择!而且相熟Java之后,就好比先学会了易筋经、九阴九阳等浅近内功,再去学习其余编程语言就很轻松了。所以作为一个过来人,强烈建议老手小白抉择Java来作为本人的编程“母语”! 另外ps一下,本系列文章,会利用文章联合视频一起给大家进行常识解说,只为让大家能够尽快学会Java,少走不必要的弯路。 四. 结语明天这篇文章,算是《从零开始学Java系列》的前奏,献给对编程齐全没有多少概念的小白敌人。接下来在下一篇文章中,就正式给大家上干货教程了,筹备学习Java的童鞋们,请从下一篇文章开始,拿出小本本,做好学习笔记哦。壹哥在下一篇文章里等你!

April 10, 2023 · 1 min · jiezi

关于java:多库多表场景下使用-Amazon-EMR-CDC-实时入湖最佳实践

一、前言CDC(Change Data Capture) 从狭义上讲所有可能捕捉变更数据的技术都能够称为 CDC,但本篇文章中对 CDC 的定义限定为以非侵入的形式实时捕捉数据库的变更数据。例如:通过解析 MySQL 数据库的 Binlog 日志捕捉变更数据,而不是通过 SQL Query 源表捕捉变更数据。 Hudi 作为最热的数据湖技术框架之一, 用于构建具备增量数据处理管道的流式数据湖。其外围的能力包含对象存储上数据行级别的疾速更新和删除,增量查问(Incremental queries,Time Travel),小文件治理和查问优化(Clustering,Compactions,Built-in metadata),ACID 和并发写反对。Hudi 不是一个 Server,它自身不存储数据,也不是计算引擎,不提供计算能力。其数据存储在 S3(也反对其它对象存储和 HDFS),Hudi 来决定数据以什么格局存储在 S3(Parquet,Avro,…), 什么形式组织数据能让实时摄入的同时反对更新,删除,ACID 等个性。Hudi 通过 Spark,Flink 计算引擎提供数据写入, 计算能力,同时也提供与 OLAP 引擎集成的能力,使 OLAP 引擎可能查问 Hudi 表。从应用上看 Hudi 就是一个 JAR 包,启动 Spark, Flink 作业的时候带上这个 JAR 包即可。Amazon EMR 上的 Spark,Flink,Presto ,Trino 原生集成 Hudi, 且 EMR 的 Runtime 在 Spark,Presto 引擎上相比开源有2倍以上的性能晋升。 在多库多表的场景下(比方:百级别库表),当咱们须要将数据库(mysql,postgres,sqlserver,oracle,mongodb 等)中的数据通过 CDC 的形式以分钟级别(1minute+)提早写入 Hudi,并以增量查问的形式构建数仓档次,对数据进行实时高效的查问剖析时。咱们要解决三个问题,第一,如何应用对立的代码实现百级别库表 CDC 数据并行写入 Hudi,升高开发保护老本。第二,源端 Schema 变更如何同步到 Hudi 表。第三,应用 Hudi 增量查问构建数仓档次比方 ODS->DWD->DWS (各层均是 Hudi 表),DWS 层的增量聚合如何实现。本篇文章举荐的计划是: 应用 Flink CDC DataStream API (非 SQL)先将 CDC 数据写入 Kafka,而不是间接通过 Flink SQL 写入到 Hudi 表,次要起因如下,第一,在多库表且 Schema 不同的场景下,应用 SQL 的形式会在源端建设多个 CDC 同步线程,对源端造成压力,影响同步性能。第二,没有 MSK 做 CDC 数据上下游的解耦和数据缓冲层,上游的多端生产和数据回溯比拟艰难。CDC 数据写入到 MSK 后,举荐应用 Spark Structured Streaming DataFrame API 或者 Flink StatementSet 封装多库表的写入逻辑,但如果须要源端 Schema 变更主动同步到 Hudi 表,应用 Spark Structured Streaming DataFrame API 实现更为简略,应用 Flink 则须要基于 HoodieFlinkStreamer 做额定的开发。Hudi 增量 ETL 在 DWS 层须要数据聚合的场景的下,能够通过 Flink Streaming Read 将 Hudi 作为一个无界流,通过 Flink 计算引擎实现数据实时聚合计算写入到 Hudi 表。 ...

April 10, 2023 · 8 min · jiezi

关于java:PMD插件你必须掌握的代码质量工具

当今的软件开发须要应用许多不同的工具和技术来确保代码品质和稳定性。PMD是一个风行的动态代码剖析工具,能够帮忙开发者在编译代码之前发现潜在的问题。在本文中,咱们将探讨如何在Gradle中应用PMD,并介绍一些最佳实际。 什么是PMD?PMD是一个用于Java代码的动态代码剖析工具。它能够帮忙开发者找出潜在的问题,如代码反复、未应用的变量、谬误的异样解决等。PMD反对多种规定,能够依据具体我的项目的须要进行配置。其工作原理参考How PMD Works。 PMD反对通过命令行界面(CLI, Command Line Interface for batch scripting)和其余多种集成形式,比方Maven、Gradle、Java API等等。 PMD在Gradle中配置和应用Gradle中自带了PMD插件,插件的默认版本能够通过源码DEFAULT_PMD_VERSION晓得。应用和配置能够参考The PMD Plugin,页面左上角能够抉择Gradle版本,确保查看的版本和你应用的Gradle版本统一,因为很多PMD的配置属性或者性能不肯定在每个版本都有。 通过页面左上角选了其余版本后跳转的地址是Gradle文档的首页,而不是PMD插件的文档页。咱们能够通过批改The PMD Plugin链接中的8.0.2为其余版本号即可跳转到对应Gradle版本蕴含的PMD插件文档的页面。比方: 以后最新版:https://docs.gradle.org/current/userguide/pmd_plugin.html 7.3.3版本:https://docs.gradle.org/7.3.3/userguide/pmd_plugin.html 在我的项目build.gradle文件中减少以下内容利用插件和扩大PMD,参考Usage和Configuration,更多的配置属性能够参考PmdExtension。 plugins { id 'pmd'}pmd { // 是否将 PMD 后果输入到终端 consoleOutput = true // 要应用的PMD版本 toolVersion = "6.21.0" // 规定优先级阈值,低于这个优先级则会被疏忽 rulesMinimumPriority = 5 // 应用的规定集配置文件门路 ruleSets = ["category/java/errorprone.xml", "category/java/bestpractices.xml"]}插件会生成两个次要的PMD TaskpmdMain和pmdTest别离对main和test两个我的项目源文件目录应用PMD进行代码查看。 找到IDEA Gradle窗口 > Tasks > other,双击生成的Task;或者在我的项目根目录运行./gradlew pmdMain都能够运行PMD。查看后果将输入到终端中(前提是配置了consoleOutput = true),违反了PMD规定的类会给出残缺的跳转门路以及规定提示信息。 最初还会给出一个报告的地址,内容蕴含了输入到终端的信息。Problem列出了规定的提醒,点击能够跳转到PMD规定形容文档对应的地位。 Gradle PMD Plugin扩大属性在这里咱们将PMD插件的扩大属性作用进行阐明,参考PmdExtension,这个文档具体阐明了各个属性的作用、默认值和配置示例。如果文档形容的不是很分明也能够参考PMD CLI options的对应形容。 consoleOutput是否将后果输入到终端(System.out)允许值为true|false。 ...

April 9, 2023 · 2 min · jiezi

关于java:推荐算法在商城系统实践

一、简介本文博主给大家解说如何在本人开源的电商我的项目newbee-mall-pro中利用协同过滤算法来达到给用户更好的购物体验成果。 newbee-mall-pro我的项目地址: 源码地址:https://github.com/wayn111/newbee-mall-pro在线地址:http://121.4.124.33/newbeemall二、协同过滤算法协同过滤算法是一种基于用户或者物品的类似度来举荐商品的办法,它能够无效地解决商城零碎中的信息过载问题。协同过滤算法的实际次要包含以下几个步骤: 数据收集和预处理。这一步须要从商城零碎中获取用户的行为数据,如浏览、购买、评估等,而后进行一些必要的荡涤和转换,以便后续的剖析和计算。类似度计算。这一步须要依据用户或者物品的特色或者行为,采纳适合的类似度度量办法,如余弦类似度、皮尔逊相关系数、Jaccard指数等,来计算用户之间或者物品之间的类似度矩阵。举荐生成。这一步须要依据类似度矩阵和用户的历史行为,采纳适合的举荐策略,如基于邻域的办法、基于模型的办法、基于矩阵合成的办法等,来生成针对每个用户的个性化举荐列表。举荐评估和优化。这一步须要依据一些评估指标,如准确率、召回率、覆盖率、多样性等,来评估举荐零碎的成果,并依据反馈信息和业务需要,进行一些参数调整和算法优化,以进步举荐零碎的性能和用户满意度。在原有的商城首页为你举荐栏目是应用后盾配置的商品列表,基于人为配置。在我的项目商品用户持续增长的状况下,不肯定能给用户举荐用户可能想要的商品。 因而在v2.4.1版本中,商城首页为你举荐栏目增加了协同过滤算法。依照UserCF基于用户的协同过滤、ItemCF基于物品的协同过滤。 实现了两种不同的举荐逻辑。 UserCF:基于用户的协同过滤。当一个用户A须要个性化举荐的时候,咱们能够先找到和他有类似趣味的其余用户,而后把那些用户喜爱的,而用户A没有据说过的物品举荐给A。假如用户 A 喜爱物品 A、物品 C,用户 B 喜爱物品 B,用户 C 喜爱物品 A 、物品 C 和物品 D;从这些用户的历史爱好信息中,咱们能够发现用户 A 和用户 C 的口味和偏好是比拟相似的,同时用户 C 还喜爱物品 D,那么咱们能够推断用户 A 可能也喜爱物品 D,因而能够将物品 D 举荐给用户 A。具体代码在 ltd.newbee.mall.recommend.core.UserCF 中。itemCF:基于物品的协同过滤。事后依据所有用户的历史偏好数据计算物品之间的类似度,而后把与用户喜爱的物品相相似的物品举荐给用户。 如果用户A喜爱物品A和物品C,用户B喜爱物品A、物品B和物品C,用户C喜爱物品A,从这些用户的历史爱好中能够认为物品A与物品C比拟相似,喜爱物品A的都喜爱物品C,基于这个判断用户C可能也喜爱物品C,所以举荐零碎将物品C举荐给用户C。 具体代码在 ltd.newbee.mall.recommend.core.ItemCF 中。三、举荐算法代码实际3.1 数据收集和预处理在newbee-mall-pro中,咱们基于用户下单的商品数据进行收集和预处理。 /** * 依据所有用户购买商品的记录进行数据手机 * * @return List<RelateDTO> */@Overridepublic List<RelateDTO> getRelateData() { List<RelateDTO> relateDTOList = new ArrayList<>(); // 获取所有订单以及订单关联商品的汇合 List<Order> newBeeMallOrders = orderDao.selectOrderIds(); List<Long> orderIds = newBeeMallOrders.stream().map(Order::getOrderId).toList(); List<OrderItemVO> newBeeMallOrderItems = orderItemDao.selectByOrderIds(orderIds); Map<Long, List<OrderItemVO>> listMap = newBeeMallOrderItems.stream() .collect(Collectors.groupingBy(OrderItemVO::getOrderId)); Map<Long, List<OrderItemVO>> goodsListMap = newBeeMallOrderItems.stream() .collect(Collectors.groupingBy(OrderItemVO::getGoodsId)); // 遍历订单,生成预处理数据 for (Order newBeeMallOrder : newBeeMallOrders) { Long orderId = newBeeMallOrder.getOrderId(); for (OrderItemVO newBeeMallOrderItem : listMap.getOrDefault(orderId, Collections.emptyList())) { Long goodsId = newBeeMallOrderItem.getGoodsId(); Long categoryId = newBeeMallOrderItem.getCategoryId(); RelateDTO relateDTO = new RelateDTO(); ... relateDTOList.add(relateDTO); } } return relateDTOList;}3.2 类似度计算在举荐算法中,类似度建设是一个十分重要的过程,它标记着算法准不精确,能不能给用户带来好的举荐体验。在newbee-mall-pro中,咱们将用户之间下单的商品进行类似度计算,因为如果两个用户购买了同一个商品,那么咱们认为这两个用户之间是存在分割并且都存在付费行为。 ...

April 9, 2023 · 4 min · jiezi

关于java:解决-HttpServletRequest-的输入流不能重复读的问题

背景写代码的时候遇到 HttpServletRequest 里的数据为null, 感觉很奇怪,同样的申请,方才还不为null。 排查通过debug发现,HttpServletRequest 在 106行 之前有值, 但在106行之后为null。 而这个办法只是简略地读了一遍 httpServletRequest 外面的数据 ServletInputStream inputStream = httpServletRequest.getInputStream()StringBuilder sb = new StringBuilder();try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset()))) { String line; while ((line = reader.readLine()) != null) { sb.append(line); }} catch (IOException e) { throw new RuntimeException(e);}return sb.toString();于是猜测 HttpServletRequest里的 inputStream 只能读一次? 去查了一下果真如此。上面理解一下起因。 HttpServletRequest的输出流只能读取一次的起因首先咱们应用 httpServletRequest.getInputStream() 返回的是 ServletInputStream 类, 它继承于 InputStream。 而咱们对这个流读数据其实 调用了 InputStream的 read()办法。 读取流的时候会依据position来获取以后地位,每读取一次,该标记就会挪动一次,如果读到最初,read()返回-1,示意曾经读取完了。 while(inputStream.read(b)) != -1) { }如果想要从新读取,能够调用 inputstream.reset() 办法, ...

April 8, 2023 · 2 min · jiezi

关于java:如何保证-Java-应用安全标准答案来了-龙蜥技术

文/ 林子熠,云原生秘密计算 SIG Maintainer “请问我怎么能力保障 Java 程序内存中明码的平安呢?” 如果你也过有相似的问题,并且在网上搜到一些并不非常欠缺却又无可奈何的答案,阐明你就是 Java 程序安全性问题的 stakeholder。 这个问题的标准答案是 Java 秘密计算技术,它将秘密计算技术引入 Java 的世界,为 Java 程序的安全性带来了重大的晋升。基于此,龙蜥社区云原生秘密计算 SIG 推出了 Java 秘密计算的具体实现技术——Teaclave Java TEE SDK, 以下简称 Teaclave Java。该技术具备以下显著长处: 全场景安全性。当用户有秘密计算硬件反对时,Teaclave Java 能够实现最高安全等级的 Java 可信计算;当用户没有相干硬件时,进化为平安沙箱隔离级别的可信计算,亦可无效爱护用户的敏感数据和计算过程的安全性。开发和构建简略。基于 SPI 的纯 Java 编程模型,一键式构建,将 Java 秘密计算开发构建门槛一降到底。Teaclave Java 曾经过企业级外部场景的验证,在 Apache 社区开源。形容本技术的论文由龙蜥社区云原生秘密计算 SIG 与上海交通大学、大连理工大学单干发表在软件工程顶会 ICSE 2023(https://conf.researchr.org/home/icse-2023)上,并且取得了本届会议的 ACM SIGSOFT 卓越论文奖。这是 2020 年以来,龙蜥社区云原生秘密计算 SIG、上海交通大学、大连理工大学首次获此殊荣。 01 问题的实质这个问题的实质是如何在具备危险的运行时环境中平安地应用敏感数据。当咱们在运行时将明码解密后,明码就会以明文的模式存在于内存中,也就是 Java 的堆上,如图 1 的左半局部所示。如果零碎蒙受攻打,比方 2021 年声名大噪的 log4j 破绽攻打,Java 堆上的内容就会被窃取。即使没有被攻打,在为了性能诊断而做 heap dump 时也有可能被动将敏感信息透露进来。所以将诸如明码这样的平安敏感信息裸露在一般运行环境具备高度的危险。 (图 1 奢侈的 Java 密码保护示意图) ...

April 7, 2023 · 6 min · jiezi

关于java:如何向Word文档中添加文本水印和图片水印

水印是在文档或图片上增加的一种通明或半透明的标记,通常用于爱护文档版权、避免盗用、确认文件归属等目标,通常蕴含文字、图像等多种元素。通过Microsoft Word 能够向文档增加文本和图片水印。除此之外,咱们也能够利用Free Spire.Doc for Java库,以编程的办法实现该性能。上面是具体的办法和示例代码。 导入jar包在进行操作之前,请先将jar导入到Java程序中,有以下两种导入办法:办法一:如果您应用的是 maven,能够通过增加以下代码到我的项目的 pom.xml 文件中,将 jar文件导入到应用程序中。 <repositories> <repository> <id>com.e-iceblue</id> <name>e-iceblue</name> <url>https://repo.e-iceblue.cn/repository/maven-public/</url> </repository></repositories><dependencies> <dependency> <groupId>e-iceblue</groupId> <artifactId>spire.doc.free</artifactId> <version>5.2.0</version> </dependency></dependencies>办法二:如果没有应用 maven,则能够从此链接下载Free Spire.Doc for Java,找到lib文件夹下的Spire.doc.jar并进行解压;而后在IDEA中创立一个新我的项目,顺次点击“文件”(File),“我的项目构造”(Project Structure),“组件”(Modules),“依赖项”(Dependencies),再点击右方绿色“+”下的第一个选项“jar文件或门路”(JARs or Directories),找到解压后的Spire.doc.jar 文件,点击确认,将其导入到我的项目中。 增加文本水印具体步骤: 创立一个 Document 实例。应用 Document.loadFromFile() 办法加载示例 Word 文档。应用 Document.getSections().get() 办法获取第一节。创立一个 TextWatermark 实例。应用 TextWatermark 类提供的办法设置文本水印的文本、字体大小、色彩和布局。应用 Section.getDocument().setWatermark() 办法将文本水印增加到示例文档。应用 Document.saveToFile() 办法保留文件。示例代码: import com.spire.doc.*;import com.spire.doc.documents.WatermarkLayout;import java.awt.*;public class WordTextWatermark { public static void main(String[] args) { //创立一个Document实例 Document document = new Document(); //加载示例 Word 文档 document.loadFromFile("sample.docx"); //获取第一节 Section section = document.getSections().get(0); //创立一个 TextWatermark 实例 TextWatermark txtWatermark = new TextWatermark(); //设置文本水印格局 txtWatermark.setText("秘密"); txtWatermark.setFontSize(40); txtWatermark.setColor(Color.red); txtWatermark.setLayout(WatermarkLayout.Diagonal); //将文本水印增加到示例文档 section.getDocument().setWatermark(txtWatermark); //保留文件 document.saveToFile("result1.docx", FileFormat.Docx); }} ...

April 7, 2023 · 1 min · jiezi

关于java:java编程中的CS模式和BS模式

随着社会信息的倒退,Java技术曾经无处不在,无论是手机软件、手机Java游戏还是电脑软件等,只有你应用到电子产品就会碰到和Java无关的货色,更多的企业正采纳Java语言开发网站,越来越多的程序员也应声而起,在学习Java的过程中总会遇到这样或那样的问题,明天千锋小编就大家分享一下C/S模式和B/S模式相干知识点。 一、C/S模式 概述:C/S模式就是大家所相熟的client(客户端)/server(服务器端)构造,它是一种软件系统体系结构。这里的客户端能够是由java图形界面(GUI)定制的软件、能够是浏览器、也能够是通过SSH拜访服务器的命令行脚本等。长处: (1)、因为C/S构造大部分的运算都是在客户端进行的,所以效率大大提高,速度也会有所晋升。 (2)、C/S构造的用户界面能够自定义,丰富多彩。 (3)、安全性有所保障,能够进行屡次认证(影响速度)等。 毛病: (1)、编写界面比拟艰难,实用面比拟窄,罕用于局域网中。 (2)、用户群体比拟固定,不适宜一些不可知的用户或终端。 (3)、降级保护比拟艰难,一次降级, 二、B/S模式 概述:B/S模式就是大家所相熟的browser(浏览器端)/server(服务器端)构造,它是一种软件系统体系结构。这里的客户端能够是各大浏览器及其版本,如:ie、火狐、safari、chrome等。 长处: (1)、无需本人编写客户端,由各大浏览器厂家编写测试实现,大大减少程序员的工作量。 (2)、交互性比拟强,能够通过服务器端管制客户端的拜访权限,达到对用户管制。 (3)、降级零碎毋庸每一个客户端都进行降级,只须要在服务器端进行网站降级即可达到目标。 (4)、编写拜访极其不便,常利用于广域网。 毛病: (1)、不同浏览器其兼容性不太欠缺,导致网页千差万别。 (2)、在速度和安全性上的投入远远大于C/S构造。 (3)、依赖性比拟强(依据浏览器厂家而定)。 4、图例:

April 7, 2023 · 1 min · jiezi

关于java:IO流中线程模型总结

IO流模块:常常看、常常用、常常忘;一、根底简介在IO流的网络模型中,以常见的「客户端-服务端」交互场景为例; 客户端与服务端进行通信「交互」,可能是同步或者异步,服务端进行「流」解决时,可能是阻塞或者非阻塞模式,当然也有自定义的业务流程须要执行,从解决逻辑看就是「读取数据-业务执行-应答写数据」的模式; Java提供「三种」IO网络编程模型,即:「BIO同步阻塞」、「NIO同步非阻塞」、「AIO异步非阻塞」; 二、同步阻塞1、模型图解BIO即同步阻塞,服务端收到客户端的申请时,会启动一个线程解决,「交互」会阻塞直到整个流程完结; 这种模式如果在高并发且流程简单耗时的场景下,客户端的申请响应会存在重大的性能问题,并且占用过多资源; 2、参考案例【服务端】启动ServerSocket接管客户端的申请,通过一系列逻辑之后,向客户端发送音讯,留神这里线程的10秒休眠; public class SocketServer01 { public static void main(String[] args) throws Exception { // 1、创立Socket服务端 ServerSocket serverSocket = new ServerSocket(8080); // 2、办法阻塞期待,直到有客户端连贯 Socket socket = serverSocket.accept(); // 3、输出流,输入流 InputStream inStream = socket.getInputStream(); OutputStream outStream = socket.getOutputStream(); // 4、数据接管和响应 int readLen = 0; byte[] buf = new byte[1024]; if ((readLen=inStream.read(buf)) != -1){ // 接收数据 String readVar = new String(buf, 0, readLen) ; System.out.println("readVar======="+readVar); } // 响应数据 Thread.sleep(10000); outStream.write("sever-8080-write;".getBytes()); // 5、资源敞开 IoClose.ioClose(outStream,inStream,socket,serverSocket); }}【客户端】Socket连贯,先向ServerSocket发送申请,再接管其响应,因为Server端模仿耗时,Client处于长时间阻塞状态; ...

April 7, 2023 · 4 min · jiezi

关于java:在Linux部署RocketMQ完整过程

前言本文讲述 RocketMQ 从源码编译到配置启动以及测试的残缺过程。 筹备工作装置 64bit JDK 1.8+参考 装置 Maven 3.2.x+Linux 工夫同步yum install ntpdate -yntpdate time.windows.com部署步骤下载 / 编译从 GitHub 下载 后编译(也能够从 Apache RocketMQ - releases 下载,或者走前面一步间接下载编译后的包)echo "先创立独自目录" > /dev/nullmkdir -p ~/soft/rocketmqecho "从 GitHub 下载源码" > /dev/nullwget -P ~/soft/rocketmq https://github.com/apache/rocketmq/archive/refs/tags/rocketmq-all-4.9.1.tar.gzecho "解压到指定目录" > /dev/nulltar -xf ~/soft/rocketmq/rocketmq-all-4.9.1.tar.gz -C ~/soft/rocketmqecho "进入解压目录" > /dev/nullcd ~/soft/rocketmq/rocketmq-rocketmq-all-4.9.1echo "编译" > /dev/nullmvn -Prelease-all -DskipTests clean install -U -f ~/soft/rocketmq/rocketmq-rocketmq-all-4.9.1echo "拷贝编译后的目录到/opt/soft"cp -r ~/soft/rocketmq/rocketmq-rocketmq-all-4.9.1/distribution/target/rocketmq-4.9.1/rocketmq-4.9.1/ /opt/soft/跳过源码编译,从 Apache 下载编译后的包echo "从 Apache 下载编译后的包" > /dev/nullwget -P ~/soft/rocketmq https://dlcdn.apache.org/rocketmq/4.9.1/rocketmq-all-4.9.1-bin-release.zipecho "解压" > /dev/nullunzip ~/test/rocketmq/rocketmq-all-4.9.1-bin-release.zip -d /opt/soft/echo "批改目录名" > /dev/nullmv /opt/soft/rocketmq-all-4.9.1-bin-release/ /opt/soft/rocketmq-4.9.1批改启动参数启动脚本中设置的 JVM 内存参数很大,如果服务器内存不够的话能够按这一步调小一点。这里只是测试所以设置很小,生产环境能够默认或者更大一点。批改 Name Server 堆内存大小(比方 -Xms512m -Xmx512m -Xmn256m)。 ...

April 6, 2023 · 1 min · jiezi

关于java:单机最快的队列Disruptor解析和使用

前言介绍高性能队列Disruptor原理以及应用例子。 Disruptor是什么?Disruptor是外汇和加密货币交易所运营商 LMAX group 建设高性能的金融交易所的后果。用于解决生产者、消费者及其数据存储的设计问题的高性能队列实现。能够对标JDK中的ArrayBlockingQueue。是目前单机且基于内存存储的最高性能的队列实现。见 与ArrayBlockingQueue性能比照。 Disruptor高性能秘诀应用CAS代替锁锁十分低廉,因为它们在竞争时须要仲裁。这种仲裁是通过到操作系统内核的上下文切换来实现的,该内核将挂起期待锁的线程,直到它被开释。零碎提供的原子操作CAS(Compare And Swap/Set)是很好的锁代替计划,Disruptor中同步就是应用的这种。 比方多生产者模式中com.lmax.disruptor.MultiProducerSequencer就是用了Java里sun.misc.Unsafe类基于CAS实现的API。 期待策略com.lmax.disruptor.BlockingWaitStrategy应用了基于CAS实现的ReentrantLock。 独占缓存行为了提高效率CPU硬件不会以字节或字为单位挪动内存,而是以缓存行,通常大小为 32-256 字节的缓存行,最常见的缓存行是 64 字节。这意味着,如果两个变量在同一个缓存行中,并且由不同的线程写入,那么它们会呈现与单个变量雷同的写入争用问题。为了取得高性能,如果要最小化争用,那么确保独立但同时写入的变量不共享雷同的缓存行是很重要的。 比方com.lmax.disruptor.RingBuffer中属性前后都用未赋值的long来独占。com.lmax.disruptor.SingleProducerSequencerPad也有雷同解决形式。 环形队列应用有界队列,缩小线程争用队列相比链表在访问速度上占据劣势,而有界队列相比可动静扩容的无界队列则防止扩容产生的同步问题效率更高。Disruptor和JDK中的ArrayBlockingQueue一样应用有界队列。队列长度要设为2的n次幂,有利于二进制计算。 应用环形数组,防止生产和生产速度差别导致队列头和尾争用Disruptor在逻辑上将数组的的头尾看成是相连的,即一个环形数组(RingBuffer)。 Sequence生产和生产都须要保护自增序列值(Sequence),从0开始。 生产方只保护一个代表生产的最初一个元素的序号。代表生产的最初一个元素的序号。每次向Disruptor公布一个元素都调用Sequenced.next()来获取下个地位的写入权。 在单生产者模式(SINGLE)因为不存在并发写入,则不须要解决同步问题。在多生产者模式(MULTI)就须要借助JDK中基于CAS(Compare And Swap/Set)实现的API来保障线程平安。 多个消费者各自保护本人的生产序列值(Sequence)保留数组中。 而环形通过与运算(sequence & indexMask)实现的,indexMask就是环形队列的长度-1。以环形队列长度8为例,第9个元素Sequence为8,8 & 7 = 0,刚好又回到了数组第1个地位。 见com.lmax.disruptor.RingBuffer.elementAt(long sequence) 预分配内存环形队列寄存的是Event对象,而且是在Disruptor创立的时候调用EventFactory创立并一次将队列填满。Event保留生产者生产的数据,生产也是通过Event获取,后续生产则只须要替换掉Event中的属性值。这种形式防止了反复创建对象,升高JVM的GC产频率。 见com.lmax.disruptor.RingBuffer.fill(EventFactory<E> eventFactory) 消费者8种期待策略当生产速度大于生产速度状况下,消费者执行的期待策略。 策略类名形容BlockingWaitStrategy(罕用)应用ReentrantLock,失败则进入期待队列期待唤醒重试。当吞吐量和低提早不如CPU资源重要时应用。YieldingWaitStrategy(罕用)尝试100次,全失败后调用Thread.yield()让出CPU。该策略将应用100%的CPU,如果其余线程申请CPU资源,这种策略更容易让出CPU资源。SleepingWaitStrategy(罕用)尝试200次 。前100次间接重试,后100次每次失败后调用Thread.yield()让出CPU,全失败线程睡眠(默认100纳秒 )。BusySpinWaitStrategy线程始终自旋期待,比拟耗CPU。最好是将线程绑定到特定的CPU外围上应用。LiteBlockingWaitStrategy与BlockingWaitStrategy相似,区别在减少了原子变量signalNeeded,如果两个线程同时别离拜访waitFor()和signalAllWhenBlocking(),能够缩小ReentrantLock加锁次数。LiteTimeoutBlockingWaitStrategy与LiteBlockingWaitStrategy相似,区别在于设置了阻塞工夫,超过工夫后抛异样。TimeoutBlockingWaitStrategy与BlockingWaitStrategy相似,区别在于设置了阻塞工夫,超过工夫后抛异样。PhasedBackoffWaitStrategy依据工夫参数和传入的期待策略来决定应用哪种期待策略。当吞吐量和低提早不如CPU资源重要时,能够应用此策略。消费者序列所有消费者的生产序列(Sequence)都放在一个数组中,见com.lmax.disruptor.AbstractSequencer,通过SEQUENCE_UPDATER来更新对应的序列值。 调用更新的中央在com.lmax.disruptor.RingBuffer.addGatingSequences(Sequence... gatingSequences)。 生产太慢队列满了怎么办?生产者线程被阻塞。生产者调用Sequenced.next()抢夺写入权的时候须要判断最小的生产序列值进行比拟。如果写入的地位还未生产则会进入循环不断获取最小生产序列值进行比拟。 见包com.lmax.disruptor下SingleProducerSequencer或MultiProducerSequencer中next(int n)办法。 Disruptor开发步骤创立Event、EventFactory、EventHandler和ExceptionHandler类Event是环形队列(RingBuffer)中的元素,是生产者数据的载体;EventFactory是定义Event创立形式的工厂类;EventHandler则是Event的处理器,定义如何生产Event中的数据。 另外有必要定义一个生产异样处理器ExceptionHandler,它是和EventHandler绑定的。当EventHandler.onEvent()执行抛出异样时会执行对应的异样回调办法。 实例化Disruptor创立Disruptor须要指定5个参数eventFactory、ringBufferSize、threadFactory、producerType、waitStrategy。 EventFactory是下面定义的Event工厂类; ringBufferSize是环形队列的长度,这个值要是2的N次方; threadFactory是定义消费者线程创立形式的工厂类; producerType是指明生产者是一个(SINGLE)还是多个(MULTI)。默认是MULTI,会应用CAS(Compare And Swap/Set)保障线程平安。如果指定为SINGLE,则不应用没必要的CAS,使单线程解决更高效。 waitStrategy指明消费者期待生产时的策略。 设置消费者指明EventHandler并绑定ExceptionHandler。指定多个EventHandler时,会为每个EventHandler调配一个线程,一个Event会被多个并行EventHandler解决。 也能够指明多个WorkHandler,每个WorkHandler调配一个线程并行生产队列中的Event,一个Event只会被一个WorkHandler解决。 创立/实例化EventTranslatorEventTranslator定义生产者数据转换为Event的形式,不同数量参数有不同的接口用来实现。 最初用Disruptor.publishEvent() 来公布元素指明EventTranslator和参数例子程序先引入Maven依赖<dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.4.4</version></dependency>Event/** * 事件 * * @param <T>公布的数据类型 */public class MyEvent<T> { private T data; public T getData() { return data; } public MyEvent<T> setData(T data) { this.data = data; return this; }}EventFactoryimport com.lmax.disruptor.EventFactory;/** * 创立事件的工厂 * * @param <T>公布的数据类型 */public class MyEventFactory<T> implements EventFactory<MyEvent<T>> { @Override public MyEvent<T> newInstance() { return new MyEvent<>(); }}EventHandlerimport com.lmax.disruptor.EventHandler;/** * 事件生产办法 * * @param <T>公布的数据类型 */public class MyEventHandler<T> implements EventHandler<MyEvent<T>> { @Override public void onEvent(MyEvent<T> tMyEvent, long l, boolean b) throws Exception { System.out.println(Thread.currentThread().getName() + "MyEventHandler生产:" + tMyEvent.getData()); }}ExceptionHandlerimport com.lmax.disruptor.ExceptionHandler;/** * 消费者异样处理器 * * @param <T>公布的数据类型 */public class MyExceptionHandler<T> implements ExceptionHandler<MyEvent<T>> { @Override public void handleEventException(Throwable ex, long sequence, MyEvent<T> event) { System.out.println("handleEventException"); } @Override public void handleOnStartException(Throwable ex) { System.out.println("handleOnStartException"); } @Override public void handleOnShutdownException(Throwable ex) { System.out.println("handleOnShutdownException"); }}单消费者import com.lmax.disruptor.EventTranslatorOneArg;import com.lmax.disruptor.ExceptionHandler;import com.lmax.disruptor.SleepingWaitStrategy;import com.lmax.disruptor.WaitStrategy;import com.lmax.disruptor.dsl.Disruptor;import java.util.concurrent.Executors;import java.util.concurrent.ThreadFactory;import static com.lmax.disruptor.dsl.ProducerType.SINGLE;/** * 单消费者 */public class SingleConsumerSample { public static void main(String[] args) { // 环形数组长度,必须是2的n次幂 int ringBufferSize = 1024; // 创立事件(Event)对象的工厂 MyEventFactory<String> eventFactory = new MyEventFactory<>(); // 创立消费者线程工厂 ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 期待策略 WaitStrategy waitStrategy = new SleepingWaitStrategy(); Disruptor<MyEvent<String>> disruptor = new Disruptor<>(eventFactory, ringBufferSize, threadFactory, SINGLE, waitStrategy); // 指定一个处理器 MyEventHandler<String> eventHandler = new MyEventHandler<>(); disruptor.handleEventsWith(eventHandler); // 处理器异样处理器 ExceptionHandler<MyEvent<String>> exceptionHandler = new MyExceptionHandler<>(); disruptor.setDefaultExceptionHandler(exceptionHandler); disruptor.start(); // 通过事件转换器(EventTranslator)来指明如何将公布的数据转换到事件对象(Event)中 // 这里是一个参数的转换器,另外还有两个(EventTranslatorTwoArg)、三个(EventTranslatorThreeArg) // 和多个(EventTranslatorVararg)参数的转换器能够应用,参数类型能够不一样 EventTranslatorOneArg<MyEvent<String>, String> eventTranslatorOneArg = new EventTranslatorOneArg<MyEvent<String>, String>() { @Override public void translateTo(MyEvent<String> event, long sequence, String arg0) { event.setData(arg0); } }; // 公布 for (int i = 0; i < 10; i++) { disruptor.publishEvent(eventTranslatorOneArg, "One arg " + i); } disruptor.shutdown(); }}单消费者Lambda写法这种只是投合Java8 Lambda语法个性,代码更简洁。 ...

April 6, 2023 · 4 min · jiezi

关于java:Java-缺失的特性扩展方法

什么是扩大办法扩大办法,就是可能向现有类型间接“增加”办法,而无需创立新的派生类型、从新编译或以其余形式批改现有类型。调用扩大办法的时候,与调用在类型中理论定义的办法相比没有显著的差别。 为什么须要扩大办法思考要实现这样的性能:从 Redis 取出蕴含多个商品ID的字符串后(每个商品ID应用英文逗号分隔),先对商品ID进行去重(并可能维持元素的程序),最初再应用英文逗号将各个商品ID进行连贯。 // "123,456,123,789"String str = redisService.get(someKey)传统写法: String itemIdStrs = String.join(",", new LinkedHashSet<>(Arrays.asList(str.split(","))));应用 Stream 写法: String itemIdStrs = Arrays.stream(str.split(",")).distinct().collect(Collectors.joining(","));假如在 Java 中能实现扩大办法,并且咱们为数组增加了扩大办法 toList(将数组变为 List),为 List 增加了扩大办法 toSet(将 List 变为 LinkedHashSet),为 Collection 增加了扩大办法 join(将汇合中元素的字符串模式应用给定的连接符进行连贯),那咱们将能够这样写代码: String itemIdStrs = str.split(",").toList().toSet().join(",");置信此刻你曾经有了为什么须要扩大办法的答案: 能够对现有的类库,进行间接加强,而不是应用工具类相比应用工具类,应用类型自身的办法写代码更晦涩更舒服代码更容易浏览,因为是链式调用,而不是用静态方法套娃在 Java 中怎么实现扩大办法咱们先来问问最近大火的 ChatGPT: 好吧,ChatGPT 认为 Java 外面的扩大办法就是通过工具类提供的静态方法 :)。所以接下来我将介绍一种全新的黑科技: Manifold(https://github.com/manifold-systems/manifold) 筹备条件Manifold 的原理和 Lombok 是相似的,也是在编译期间通过注解处理器进行解决。所以要在 IDEA 中正确应用 Manifold,须要装置 Manifold IDEA 的插件: 而后再在我的项目 pom 的 maven-compiler-plugin 中退出 annotationProcessorPaths: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <properties> <manifold.version>2022.1.35</manifold.version> </properties> <dependencies> <dependency> <groupId>systems.manifold</groupId> <artifactId>manifold-ext</artifactId> <version>${manifold.version}</version> </dependency> ... </dependencies> <!--Add the -Xplugin:Manifold argument for the javac compiler--> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>8</source> <target>8</target> <encoding>UTF-8</encoding> <compilerArgs> <arg>-Xplugin:Manifold no-bootstrap</arg> </compilerArgs> <annotationProcessorPaths> <path> <groupId>systems.manifold</groupId> <artifactId>manifold-ext</artifactId> <version>${manifold.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build></project>如果你的我的项目中应用了 Lombok,须要把 Lombok 也退出 annotationProcessorPaths: ...

April 6, 2023 · 3 min · jiezi

关于java:干掉复杂的工具类国产Java工具类库-Hutool-很香

Hutool 大家曾经比拟相熟了,这是一个超全的 Java 工具库,深受国内开发者的青睐。 我之前其实是不太喜爱应用这种性能太多的工具类的,也比拟放心稳定性和安全性,前面缓缓承受了就感觉其实也还好。而且,咱们还能够按需只引入本人须要的功能模块,绝对也比拟灵便。 Hutool 的官网文档介绍的曾经比拟清晰了,奈何其提供的性能切实太多,我这里列举一些我集体感觉比拟实用的性能,供大家学习参考。 Hutool 介绍 Hutool 真心是一个不错的国产 Java 工具类库,性能全面,对文件、流、加密解密、转码、正则、线程、XML 等 JDK 办法进行了封装,开箱即用! 官网是这样介绍 Hutool 的: Hutool 蕴含的组件以及组件提供的性能如下表所示: 你能够依据我的项目需要对每个模块独自引入,也能够通过引入hutool-all形式引入所有模块。不过,还是不倡议引入所有模块,因为绝大部分性能我的项目可能都用不上,倡议只引入你须要的模块。 另外,Hutool 也有一个比拟显著的毛病,很多性能实现的比较简单比方图片验证码、Excel 工具类,很可能无奈满足我的项目的理论需要。像这样状况,还是倡议你抉择在某一方面更优良的工具库比方 Excel 工具库MyExcel、EasyExcel、图片解决库Imglib。 Hutool 实战引入依赖Maven 仓库地址:https://mvnrepository.com/artifact/cn.hutool 。 这里为了不便,咱们间接引入所有模块,理论我的项目中还是倡议只引入本人须要的模块。 Maven: <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.16</version></dependency>Gradle: implementation 'cn.hutool:hutool-all:5.8.16'性能演示Hutool 提供的性能切实太多,这里只列举一些我集体感觉比拟实用的性能,供大家学习参考。 类型转换Convert 类封装了针对Java常见类型的转换。 long[] b = {1,2,3,4,5};String bStr = Convert.toStr(b);//"[1, 2, 3, 4, 5]"double a = 67556.32;String digitUppercase = Convert.digitToChinese(a);//"陆万柒仟伍佰伍拾陆元叁角贰分"邮件在 Java 中发送邮件次要品依附 javax.mail 包,然而因为应用比拟繁琐,因而 Hutool 针对其做了封装。 在classpath(在规范Maven我的项目中为src/main/resources)的config目录下新建mail.setting文件,残缺配置如下(邮件服务器必须反对并关上SMTP协定): # 邮件服务器的SMTP地址,可选,默认为smtp.<发件人邮箱后缀>host = smtp.yeah.net# 邮件服务器的SMTP端口,可选,默认25port = 25# 发件人(必须正确,否则发送失败)from = hutool@yeah.net# 用户名,默认为发件人邮箱前缀user = hutool# 明码(留神,某些邮箱须要为SMTP服务独自设置受权码,详情查看相干帮忙)pass = q1w2e3发送邮件非常简单: ...

April 6, 2023 · 2 min · jiezi

关于java:单机最快的队列Disruptor解析和使用

前言介绍高性能队列Disruptor原理以及应用例子。 Disruptor是什么?Disruptor是外汇和加密货币交易所运营商 LMAX group 建设高性能的金融交易所的后果。用于解决生产者、消费者及其数据存储的设计问题的高性能队列实现。能够对标JDK中的ArrayBlockingQueue。是目前单机且基于内存存储的最高性能的队列实现。见 与ArrayBlockingQueue性能比照。 Disruptor高性能秘诀应用CAS代替锁锁十分低廉,因为它们在竞争时须要仲裁。这种仲裁是通过到操作系统内核的上下文切换来实现的,该内核将挂起期待锁的线程,直到它被开释。零碎提供的原子操作CAS(Compare And Swap/Set)是很好的锁代替计划,Disruptor中同步就是应用的这种。 比方多生产者模式中com.lmax.disruptor.MultiProducerSequencer就是用了Java里sun.misc.Unsafe类基于CAS实现的API。 期待策略com.lmax.disruptor.BlockingWaitStrategy应用了基于CAS实现的ReentrantLock。 独占缓存行为了提高效率CPU硬件不会以字节或字为单位挪动内存,而是以缓存行,通常大小为 32-256 字节的缓存行,最常见的缓存行是 64 字节。这意味着,如果两个变量在同一个缓存行中,并且由不同的线程写入,那么它们会呈现与单个变量雷同的写入争用问题。为了取得高性能,如果要最小化争用,那么确保独立但同时写入的变量不共享雷同的缓存行是很重要的。 比方com.lmax.disruptor.RingBuffer中属性前后都用未赋值的long来独占。com.lmax.disruptor.SingleProducerSequencerPad也有雷同解决形式。 环形队列应用有界队列,缩小线程争用队列相比链表在访问速度上占据劣势,而有界队列相比可动静扩容的无界队列则防止扩容产生的同步问题效率更高。Disruptor和JDK中的ArrayBlockingQueue一样应用有界队列。队列长度要设为2的n次幂,有利于二进制计算。 应用环形数组,防止生产和生产速度差别导致队列头和尾争用Disruptor在逻辑上将数组的的头尾看成是相连的,即一个环形数组(RingBuffer)。 Sequence生产和生产都须要保护自增序列值(Sequence),从0开始。 生产方只保护一个代表生产的最初一个元素的序号。代表生产的最初一个元素的序号。每次向Disruptor公布一个元素都调用Sequenced.next()来获取下个地位的写入权。 在单生产者模式(SINGLE)因为不存在并发写入,则不须要解决同步问题。在多生产者模式(MULTI)就须要借助JDK中基于CAS(Compare And Swap/Set)实现的API来保障线程平安。 多个消费者各自保护本人的生产序列值(Sequence)保留数组中。 而环形通过与运算(sequence & indexMask)实现的,indexMask就是环形队列的长度-1。以环形队列长度8为例,第9个元素Sequence为8,8 & 7 = 0,刚好又回到了数组第1个地位。 见com.lmax.disruptor.RingBuffer.elementAt(long sequence) 预分配内存环形队列寄存的是Event对象,而且是在Disruptor创立的时候调用EventFactory创立并一次将队列填满。Event保留生产者生产的数据,生产也是通过Event获取,后续生产则只须要替换掉Event中的属性值。这种形式防止了反复创建对象,升高JVM的GC产频率。 见com.lmax.disruptor.RingBuffer.fill(EventFactory eventFactory) 消费者8种期待策略当生产速度大于生产速度状况下,消费者执行的期待策略。 消费者序列所有消费者的生产序列(Sequence)都放在一个数组中,见com.lmax.disruptor.AbstractSequencer,通过SEQUENCE_UPDATER来更新对应的序列值。 调用更新的中央在com.lmax.disruptor.RingBuffer.addGatingSequences(Sequence... gatingSequences)。 生产太慢队列满了怎么办?生产者线程被阻塞。生产者调用Sequenced.next()抢夺写入权的时候须要判断最小的生产序列值进行比拟。如果写入的地位还未生产则会进入循环不断获取最小生产序列值进行比拟。 见包com.lmax.disruptor下SingleProducerSequencer或MultiProducerSequencer中next(int n)办法。 Disruptor开发步骤创立Event、EventFactory、EventHandler和ExceptionHandler类Event是环形队列(RingBuffer)中的元素,是生产者数据的载体;EventFactory是定义Event创立形式的工厂类;EventHandler则是Event的处理器,定义如何生产Event中的数据。 另外有必要定义一个生产异样处理器ExceptionHandler,它是和EventHandler绑定的。当EventHandler.onEvent()执行抛出异样时会执行对应的异样回调办法。 实例化Disruptor创立Disruptor须要指定5个参数eventFactory、ringBufferSize、threadFactory、producerType、waitStrategy。 EventFactory是下面定义的Event工厂类; ringBufferSize是环形队列的长度,这个值要是2的N次方; threadFactory是定义消费者线程创立形式的工厂类; producerType是指明生产者是一个(SINGLE)还是多个(MULTI)。默认是MULTI,会应用CAS(Compare And Swap/Set)保障线程平安。如果指定为SINGLE,则不应用没必要的CAS,使单线程解决更高效。 waitStrategy指明消费者期待生产时的策略。 设置消费者指明EventHandler并绑定ExceptionHandler。指定多个EventHandler时,会为每个EventHandler调配一个线程,一个Event会被多个并行EventHandler解决。 也能够指明多个WorkHandler,每个WorkHandler调配一个线程并行生产队列中的Event,一个Event只会被一个WorkHandler解决。 创立/实例化EventTranslatorEventTranslator定义生产者数据转换为Event的形式,不同数量参数有不同的接口用来实现。 最初用Disruptor.publishEvent() 来公布元素指明EventTranslator和参数例子程序先引入Maven依赖<dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>3.4.4</version></dependency>Event/** * 事件 * * @param <T>公布的数据类型 */public class MyEvent<T> { private T data; public T getData() { return data; } public MyEvent<T> setData(T data) { this.data = data; return this; }}EventFactoryimport com.lmax.disruptor.EventFactory;/** * 创立事件的工厂 * * @param <T>公布的数据类型 */public class MyEventFactory<T> implements EventFactory<MyEvent<T>> { @Override public MyEvent<T> newInstance() { return new MyEvent<>(); }}EventHandlerimport com.lmax.disruptor.EventHandler;/** * 事件生产办法 * * @param <T>公布的数据类型 */public class MyEventHandler<T> implements EventHandler<MyEvent<T>> { @Override public void onEvent(MyEvent<T> tMyEvent, long l, boolean b) throws Exception { System.out.println(Thread.currentThread().getName() + "MyEventHandler生产:" + tMyEvent.getData()); }}ExceptionHandlerimport com.lmax.disruptor.ExceptionHandler;/** * 消费者异样处理器 * * @param <T>公布的数据类型 */public class MyExceptionHandler<T> implements ExceptionHandler<MyEvent<T>> { @Override public void handleEventException(Throwable ex, long sequence, MyEvent<T> event) { System.out.println("handleEventException"); } @Override public void handleOnStartException(Throwable ex) { System.out.println("handleOnStartException"); } @Override public void handleOnShutdownException(Throwable ex) { System.out.println("handleOnShutdownException"); }}单消费者import com.lmax.disruptor.EventTranslatorOneArg;import com.lmax.disruptor.ExceptionHandler;import com.lmax.disruptor.SleepingWaitStrategy;import com.lmax.disruptor.WaitStrategy;import com.lmax.disruptor.dsl.Disruptor;import java.util.concurrent.Executors;import java.util.concurrent.ThreadFactory;import static com.lmax.disruptor.dsl.ProducerType.SINGLE;/** * 单消费者 */public class SingleConsumerSample { public static void main(String[] args) { // 环形数组长度,必须是2的n次幂 int ringBufferSize = 1024; // 创立事件(Event)对象的工厂 MyEventFactory<String> eventFactory = new MyEventFactory<>(); // 创立消费者线程工厂 ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 期待策略 WaitStrategy waitStrategy = new SleepingWaitStrategy(); Disruptor<MyEvent<String>> disruptor = new Disruptor<>(eventFactory, ringBufferSize, threadFactory, SINGLE, waitStrategy); // 指定一个处理器 MyEventHandler<String> eventHandler = new MyEventHandler<>(); disruptor.handleEventsWith(eventHandler); // 处理器异样处理器 ExceptionHandler<MyEvent<String>> exceptionHandler = new MyExceptionHandler<>(); disruptor.setDefaultExceptionHandler(exceptionHandler); disruptor.start(); // 通过事件转换器(EventTranslator)来指明如何将公布的数据转换到事件对象(Event)中 // 这里是一个参数的转换器,另外还有两个(EventTranslatorTwoArg)、三个(EventTranslatorThreeArg) // 和多个(EventTranslatorVararg)参数的转换器能够应用,参数类型能够不一样 EventTranslatorOneArg<MyEvent<String>, String> eventTranslatorOneArg = new EventTranslatorOneArg<MyEvent<String>, String>() { @Override public void translateTo(MyEvent<String> event, long sequence, String arg0) { event.setData(arg0); } }; // 公布 for (int i = 0; i < 10; i++) { disruptor.publishEvent(eventTranslatorOneArg, "One arg " + i); } disruptor.shutdown(); }}单消费者Lambda写法这种只是投合Java8 Lambda语法个性,代码更简洁。 ...

April 6, 2023 · 4 min · jiezi

关于java:新一代分布式任务调度框架

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址 如果拜访不了Github,能够拜访gitee地址。 gitee地址 咱们先思考上面几个业务场景的解决方案: 领取零碎每天凌晨1点跑批,进行一天清理,每月1号进行上个月清理电商整点抢购,商品价格8点整开始优惠12306购票零碎,超过30分钟没有胜利领取订单的,进行回收解决商品胜利发货后,须要向客户发送短信揭示相似的业务场景十分多,咱们怎么解决?为什么咱们须要定时工作很多业务场景须要咱们某一特定的时刻去做某件工作,定时工作解决的就是这种业务场景。一般来说,零碎能够应用消息传递代替局部定时工作,两者有很多相似之处,能够互相替换场景。 如,下面发货胜利发短信告诉客户的业务场景,咱们能够在发货胜利后发送MQ音讯到队列,而后去生产mq音讯,发送短信。但在某些场景下不能调换: 工夫驱动/事件驱动:外部零碎个别能够通过工夫来驱动,但波及到内部零碎,则只能应用工夫驱动。如怕取内部网站价格,每小时爬一次批量解决/逐条解决:批量解决沉积的数据更加高效,在不须要实时性的状况下比消息中间件更有劣势。而且有的业务逻辑只能批量解决。如挪动每个月结算咱们的话费实时性/非实时性:消息中间件可能做到实时处理数据,然而有些状况下并不需要实时,比方:vip降级零碎外部/零碎解耦:定时任务调度个别是在零碎外部,而消息中间件可用于两个零碎间java有哪些定时工作的框架单机timer:是一个定时器类,通过该类能够为指定的定时工作进行配置。TimerTask类是一个定时工作类,该类实现了Runnable接口,毛病异样未查看会停止线程ScheduledExecutorService:绝对提早或者周期作为定时任务调度,毛病没有相对的日期或者工夫spring定时框架:配置简略性能较多,如果零碎应用单机的话能够优先思考spring定时器散布Quartz:Java事实上的定时工作规范。但Quartz关注点在于定时工作而非数据,并无一套依据数据处理而定制化的流程。尽管Quartz能够基于数据库实现作业的高可用,但短少分布式并行调度的性能TBSchedule:阿里晚期开源的分布式任务调度零碎。代码略古老,应用timer而非线程池执行任务调度。家喻户晓,timer在解决异样情况时是有缺点的。而且TBSchedule作业类型较为繁多,只能是获取/解决数据一种模式。还有就是文档缺失比较严重elastic-job:当当开发的弹性分布式任务调度零碎,功能丰富弱小,采纳zookeeper实现分布式协调,实现工作高可用以及分片,目前是版本2.15,并且能够反对云开发Saturn:是唯品会自主研发的分布式的定时工作的调度平台,基于当当的elastic-job 版本1开发,并且能够很好的部署到docker容器上。xxl-job: 是公众点评员工徐雪里于2015年公布的分布式任务调度平台,是一个轻量级分布式任务调度框架,其外围设计指标是开发迅速、学习简略、轻量级、易扩大。最全面的Java面试网站分布式任务调度零碎比照参加比照的可选零碎计划:elastic——job (以下简称E-Job)与 xxx-job(以下简称X-Job)反对集群部署X-Job:集群部署惟一要求为:保障每个集群节点配置(db和登陆账号等)保持一致。调度核心通过db配置辨别不同集群。 执行器反对集群部署,晋升调度零碎可用性,同时晋升工作解决能力。集群部署惟一要求为:保障集群中每个执行器的配置项 “xxl.job.admin.addresses/调度核心地址” 保持一致,执行器依据该配置进行执行器主动注册等操作。E-Job:重写Quartz基于数据库的分布式性能,改用Zookeeper实现注册核心 作业注册核心:基于Zookeeper和其客户端Curator实现的全局作业注册控制中心。用于注册,管制和协调分布式作业执行。多节点部署时工作不能反复执行X-Job:应用Quartz基于数据库的分布式性能 E-Job:将工作拆分为n个工作项后,各个服务器别离执行各自调配到的工作项。一旦有新的服务器退出集群,或现有服务器下线,elastic-job将在保留本次工作执行不变的状况下,下次工作开始前触发工作重分片。 日志可追溯X-Job:反对,有日志查问界面 E-Job:可通过事件订阅的形式解决调度过程的重要事件,用于查问、统计和监控。Elastic-Job目前提供了基于关系型数据库两种事件订阅形式记录事件。 监控告警X-Job:调度失败时,将会触发失败报警,如发送报警邮件。 任务调度失败时邮件告诉的邮箱地址,反对配置多邮箱地址,配置多个邮箱地址时用逗号分隔E-Job:通过事件订阅形式可自行实现 作业运行状态监控、监听作业服务器存活、监听近期数据处理胜利、数据流类型作业(可通过监听近期数据处理胜利数判断作业流量是否失常,如果小于作业失常解决的阀值,可抉择报警。)、监听近期数据处理失败(可通过监听近期数据处理失败数判断作业处理后果,如果大于0,可抉择报警。)弹性扩容缩容X-Job:应用Quartz基于数据库的分布式性能,服务器超出肯定数量会给数据库造成肯定的压力 E-Job:通过zk实现各服务的注册、管制及协调 反对并行调度X-Job:调度零碎多线程(默认10个线程)触发调度运行,确保调度准确执行,不被梗塞。 E-Job:采纳工作分片形式实现。将一个工作拆分为n个独立的工作项,由分布式的服务器并行执行各自调配到的分片项。 高可用策略X-Job:“调度核心”通过DB锁保障集群散布式调度的一致性, 一次任务调度只会触发一次执行; E-Job:调度器的高可用是通过运行几个指向同一个ZooKeeper集群的Elastic-Job-Cloud-Scheduler实例来实现的。ZooKeeper用于在以后主Elastic-Job-Cloud-Scheduler实例失败的状况下执行领导者选举。通过至多两个调度器实例来形成集群,集群中只有一个调度器实例提供服务,其余实例处于”待命”状态。当该实例失败时,集群会选举残余实例中的一个来持续提供服务。 失败解决策略X-Job:调度失败时的解决策略,策略包含:失败告警(默认)、失败重试; E-Job:弹性扩容缩容在下次作业运行前重分片,但本次作业执行的过程中,下线的服务器所调配的作业将不会从新被调配。生效转移性能能够在本次作业运行中用闲暇服务器抓取孤儿作业分片执行。同样生效转移性能也会就义局部性能。 最全面的Java面试网站动静分片策略X-Job:分片播送工作以执行器为维度进行分片,反对动静扩容执行器集群从而动静减少分片数量,协同进行业务解决;在进行大数据量业务操作时可显著晋升工作解决能力和速度。 执行器集群部署时,工作路由策略抉择”分片播送”状况下,一次任务调度将会播送触发对应集群中所有执行器执行一次工作,同时传递分片参数;可依据分片参数开发分片工作; E-Job:反对多种分片策略,可自定义分片策略 默认蕴含三种分片策略:基于平均分配算法的分片策略、 作业名的哈希值奇偶数决定IP升降序算法的分片策略、依据作业名的哈希值对Job实例列表进行轮转的分片策略,反对自定义分片策略 elastic-job的分片是通过zookeeper来实现的。分片的分片由主节点调配,如下三种状况都会触发主节点上的分片算法执行:a、新的Job实例退出集群 b、现有的Job实例下线(如果下线的是leader节点,那么先选举而后触发分片算法的执行) c、主节点选举” 和quartz框架比照调用API的的形式操作工作,不人性化;须要长久化业务QuartzJobBean到底层数据表中,零碎侵入性相当严重。调度逻辑和QuartzJobBean耦合在同一个我的项目中,这将导致一个问题,在调度工作数量逐步增多,同时调度工作逻辑逐步减轻的状况加,此时调度零碎的性能将大大受限于业务;Quartz关注点在于定时工作而非数据,并无一套依据数据处理而定制化的流程。尽管Quartz能够基于数据库实现作业的高可用,但短少分布式并行调度的性能。综合比照 总结和论断共同点: E-Job和X-job都有宽泛的用户根底和残缺的技术文档,都能满足定时工作的基本功能需要。 不同点: X-Job 偏重的业务实现的简略和治理的不便,学习老本简略,失败策略和路由策略丰盛。举荐应用在“用户基数绝对少,服务器数量在肯定范畴内”的情景下使E-Job 关注的是数据,减少了弹性扩容和数据分片的思路,以便于更大限度的利用分布式服务器的资源。然而学习老本绝对高些,举荐在“数据量宏大,且部署服务器数量较多”时应用最初给大家分享一个Github仓库,下面有大彬整顿的300多本经典的计算机书籍PDF,包含C语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生等,能够star一下,下次找书间接在下面搜寻,仓库继续更新中~ Github地址

April 6, 2023 · 1 min · jiezi

关于java:Ribbon的基础使用模板

Ribbon是Spring Cloud外围组件之一,它提供的最重要的性能就是负载平衡,和硬件负载平衡F5不同,它的负载平衡是基于客户端的,Zuul网关和Feign能够通过Ribbon轻松的实现服务的负载平衡,同时防止了与业务无关的冗余代码。 1 根本应用配置文件中配置: 服务消费者中定义userservice: #服务提供者 ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule# 负载平衡规定类代码 @Bean public IRule randomRule(){ //返回实现IRule的实例 可自定义策略 return new RandomRule(); //随机 } 能够自定义类实现 IRule 接口 而后再配置文件中配置自定义的实现类达到自定义负载平衡策略,默认策略是同一区下进行轮询 配置中能够配置区(zone)名 2 Ribbon负载平衡流程图 流程1 通过url获取服务名称2 通过服务名称去注册核心获取服务实例3 通过负载平衡策略抉择其中一个实例4 通过实例批改url,发动申请 3 懒加载和饥饿加载Ribbon默认是懒加载,当第一次拜访服务时再去拉取服务、调用 ,后续放在缓存中,第一次调用慢饥饿加载则是我的项目启动时加载服务 Ribbon改为饥饿加载的形式为: ribbon: eager-load: enabled: true # 开启饥饿加载 clients: userservice # 指定对userservice这个服务饥饿加载多个服务则改为: clients: -userservice -xxservice

April 5, 2023 · 1 min · jiezi

关于java:nacos基础使用模板注册中心配置中心

Nacos是阿里巴巴的产品,当初是SpringCloud中的一个组件。Nacos自身就是一个独自的软件,须要下载并且装置 1 注册核心一、根本应用在父工程中引入spring-cloud-alilbaba的治理依赖 <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.6.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency>在微服务中引入nacos客户端依赖 <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>在微服务的application.yml文件中增加nacos的配置文件 spring: application: name: xx-xxx-service # 利用名称 cloud: nacos: server-addr: 127.0.0.1:8848 #这里填写注册服务地址启动naocs 登录后查看是否有对应的服务注册列表一点要在服务类中写个测试接口,只有spring启动类的空我的项目注册列表不显示!!! 二、Nacos服务分级存储模型 Nacos服务分级为 一级 服务名 二级 服务实例集群 三级 服务实例设置服务实例对应的集群 配置文件中增加discovery相干的配置 spring: application: name: xx-xxx-service # 利用名称 cloud: nacos: server-addr: 127.0.0.1:8848 #这里填写注册服务地址 discovery: cluster-name: HZ # 配置集群名称,也就是机房地位,例如:HZ,杭州三、Nacos与RibbonNacos中配置ribbon相干配置为 userservice: #服务提供者服务名 ribbon: NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载平衡规定该负载平衡规定默认当初同一集群中寻找服务提供者实例,没有再在不同的集群中寻找服务列表,再随机抉择某个服务实例这样的益处:同一集群个别都在同一地点,响应工夫更快也可手动再Nacos中给每个服务实例配置权重来使某个实例应用几率更高或更低,权重值在0~1之间,越高选中概率越高,0则齐全不会被选中 三、Nacos的环境隔离Nacos中服务存储和数据存储的最外层都是一个名为namespace的货色,用来做最外层隔离Nacos中可用通过不同的命名空间把微服务分成不同的组,组与组之间无奈互相调用 Nacos新增命名空间流程:批改配置文件 spring: cloud: nacos: server-addr: localhost:8848 discovery: cluster-name: SH # 上海 namespace: 492a7d5d-237b-46a1-a99a-fa8e98e4b0f9 # 命名空间,填ID四、长期实例与非长期实例区别:长期实例宕机时,会从nacos的服务列表中剔除,而非长期实例则不会长期实例Naocs采纳心跳检测是否挂了,非长期实例Nacos被动询问监测是否挂了 ...

April 5, 2023 · 2 min · jiezi

关于java:代码Bug太多给新人Code-Review头都大了快来试试SpotBugs

如果你须要一个自动化的工具帮忙你或者你的团队发现代码中的缺点,在晋升代码品质同时缩小人工Code Review的老本,那这篇文章十分的适宜你。本文围绕SpotBugs与Gradle集成,将相干配置和应用进行了具体介绍,并提供了各种可能为你的我的项目定制化配置的伎俩。起源和出处都已在文中要害处以超链接给出,纵情享受吧。 SpotBugs是什么?SpotBugs是一个开源的Java动态剖析工具,旨在帮忙开发人员检测代码中的潜在缺点和破绽。SpotBugs能够通过扫描Java字节码来发现潜在的问题,例如空指针援用、类型转换谬误、未应用的变量等等。它还能够检测代码中的潜在安全漏洞,例如SQL注入、XSS攻打等。SpotBugs提供了一个用户敌对的GUI和命令行接口,能够轻松地与各种构建工具和IDE集成,例如Ant、Maven、Gradle、Eclipse和IntelliJ IDEA。SpotBugs还反对插件和自定义规定,使得开发人员能够依据我的项目的特定需要和规范对其进行定制化配置。更多详细信息能够查看SpotBugs官网文档。 SpotBugs是FindBugs的一个分支,它在FindBugs的根底上进行了改良和降级,它应用了更先进的算法和技术来进步剖析的准确性和效率。SpotBugs还增加了对新的Java版本的反对,例如Java 8和Java 11。SpotBugs还提供了更好的用户界面和命令行界面,并反对更多的构建工具和IDE集成。 FindBugs也是一款十分风行的Java动态剖析工具,然而曾经进行更新。停更的起因仿佛是我的项目拥有者不愿持续在这个我的项目上花工夫,代码贡献者因为没有权限也无奈持续迭代和公布新的版本,在FindBugs GitHub首页的README文件中提供了两个文档我的项目状态 2016-November和我的项目状态 2017-September,外面讲述了代码贡献者过后的一些担心和无奈。 SpotBugs与Gradle集成开始之前先简略介绍下本文中将会提到的几个依赖以及它们之间的关系,以便于了解后续内容: com.github.spotbugs.snom:spotbugs-gradle-plugin是一个Gradle插件,它将SpotBugs集成到 Gradle构建中,生成SpotBugsTask并能够通过配置属性来扩大。com.github.spotbugs:spotbugs这个依赖根本蕴含了所有SpotBugs检测器,这些检测器实现了Bug descriptions中提到的相干Bug检测项的逻辑。com.h3xstream.findsecbugs:findsecbugs-plugin在com.github.spotbugs:spotbugs的根底上减少了平安相干的查看器也就是Bug descriptions#Security中形容的相关检查项。com.github.spotbugs:spotbugs-annotations是Spotbugs的一个扩大/辅助工具,开发者应用这外面注解能够让Spotbugs依照咱们的用意来查看代码。spotbugs-gradle-pluginspotbugs-gradle-plugin是一个Gradle插件,它将SpotBugs集成到Gradle构建中,生成SpotBugsTask并提供相干配置来扩大,运行SpotBugsTask就能够执行查看,生成报告等。 默认状况下,这个插件外面曾经蕴含了一个spotbugs,所以利用了这个插件后个别无需在另外增加com.github.spotbugs:spotbugs。从SpotBugs version mapping中能够晓得spotbugs-gradle-plugin不同版本中默认蕴含的spotbugs版本之间的关系,比方:com.github.spotbugs.snom:spotbugs-gradle-plugin:5.0.13蕴含了com.github.spotbugs:spotbugs:4.7.3。 SpotBugs Gradle插件要求Gradle版本为7.0或者更高,JDK版本为1.8或者更高。 这个插件会为每个sourceSets生成SpotBugsTask。例如我的项目中有两个sourceSets main和test,插件将生成两个SpotBugsTask(spotbugsMain和spotbugsTest)。 如果不想主动生成SpotBugsTask,能够应用SpotBugs Base插件从头开始配置,参考com.github.spotbugs-base。 生成的SpotBugsTask执行时须要编译后的.class文件作为输出,因而它们将在Java编译后运行。SpotBugs Gradle减少了check相干的工作依赖,所以简略的运行./gradlew check也会执行生成的SpotBugsTask。 参考com.github.spotbugs在build.gradle文件中减少以下内容来引入SpotBugs Gradle插件: buildscript { repositories { maven { url "https://plugins.gradle.org/m2/" } } dependencies { classpath "com.github.spotbugs.snom:spotbugs-gradle-plugin:5.0.13" }}apply plugin: "com.github.spotbugs"插件外面提供了很多可选的属性来配置或者扩大插件的行为。 上面展现了在build.gradle文件减少spotbugs{}相干属性的例子,详细信息能够参考SpotBugsExtension,这外面有每个属性作用、可指定的值和其余相干信息。spotbugs{}中指定的大部分属性将作为生成的SpotBugsTask配置的默认值,意味着能够通过spotbugs{}给所有SpotBugsTask配置属性。 spotbugs { ignoreFailures = false showStackTraces = true showProgress = false reportLevel = 'default' effort = 'default' visitors = [ 'FindSqlInjection', 'SwitchFallthrough' ] omitVisitors = [ 'FindNonShortCircuit' ] reportsDir = file("$buildDir/reports/spotbugs") includeFilter = file('spotbugs-include.xml') excludeFilter = file('spotbugs-exclude.xml') onlyAnalyze = ['com.foobar.MyClass', 'com.foobar.mypkg.*'] projectName = name release = version extraArgs = [ '-nested:false' ] jvmArgs = [ '-Duser.language=ja' ] maxHeapSize = '512m'}除了上述形式外,还可间接配置SpotBugsTask,以设置某个工作特定的属性,比方上面为名为spotbugsMain的工作独自进行了设置,跟spotbugs{}同名的属性将被笼罩,详细信息参考SpotBugsTask。 ...

April 5, 2023 · 3 min · jiezi

关于java:设计模式大全

设计模式设计模式设计模式是指在软件设计中常常遇到的一些重复性问题所提供的可复用解决方案,它能够帮忙咱们进步软件的可维护性、可扩展性和可重用性。Java中的设计模式是基于面向对象编程思维而产生的,它们能够帮忙咱们更好地组织代码并升高代码的耦合度。 根本准则Java中的设计模式基于以下根本准则: 繁多职责准则凋谢关闭准则里氏替换准则依赖倒置准则接口隔离准则迪米特法令常见的设计模式Java中常见的设计模式包含: 工厂模式单例模式原型模式适配器模式装璜器模式代理模式观察者模式责任链模式命令模式模板办法模式策略模式设计模式是面向对象编程中十分重要的一个概念,它能够帮忙咱们更好地组织代码并进步代码的可维护性和可扩展性。在理论利用中,咱们应该依据须要抉择适合的设计模式来解决问题,防止适度应用设计模式导致代码复杂度减少。 根本准则介绍繁多职责准则繁多职责准则(SRP)是指一个类或模块只负责实现一个职责或性能。如果一个类或模块承当了多个职责或性能,那么它的职责和性能就会变得不清晰,容易呈现bug,并且难以保护和扩大。 Java示例代码: public class UserService { public void register(User user) { // 注册用户 } public void login(User user) { // 登录用户 } public void updateUser(User user) { // 更新用户信息 } public void deleteUser(User user) { // 删除用户 }}在下面的示例代码中,UserService类负责用户的注册、登录、更新和删除这四个职责,这违反了繁多职责准则。咱们能够将其拆分为四个类,每个类只负责一个职责。 凋谢关闭准则凋谢关闭准则(OCP)是指一个软件实体应该对扩大凋谢,对批改敞开。也就是说,在不批改原有代码的状况下,通过扩大它来实现新的性能。 Java示例代码: public interface Shape { void draw();}public class Rectangle implements Shape { @Override public void draw() { System.out.println("Drawing rectangle"); }}public class Circle implements Shape { @Override public void draw() { System.out.println("Drawing circle"); }}public class ShapeDrawer { private List<Shape> shapes = new ArrayList<>(); public void addShape(Shape shape) { shapes.add(shape); } public void drawShapes() { for (Shape shape : shapes) { shape.draw(); } }}在下面的示例代码中,Shape接口示意图形,Rectangle和Circle类别离实现了Shape接口。ShapeDrawer类负责绘制图形,其中addShape办法用于增加图形,drawShapes办法用于绘制所有图形。如果咱们须要新增一种图形,只须要创立一个新的类,实现Shape接口,并增加到ShapeDrawer中即可,不须要批改原有代码。 ...

April 5, 2023 · 9 min · jiezi

关于java:springboot二RestApi

第一类:申请门路参数@PathVariable获取门路参数。即url/{id}这种模式。 @RequestParam获取查问参数。即url?name=这种模式 第二类:Body参数第三类:申请头参数以及Cookie@RequestHeader@CookieValue 代码实现新建包controller新建类Studentpackage com.example.demo.controller;public class Student { private String name = ""; private int age = 1; private int id = 1; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String toString() { return "name:" + name + ";age=" + age + ";id:" + id; }}新建StudentControllerpackage com.example.demo.controller;import jakarta.servlet.http.Cookie;import jakarta.servlet.http.HttpServletRequest;import org.springframework.web.bind.annotation.*;import java.util.HashMap;import java.util.Map;@RestControllerpublic class StudentController { @RequestMapping(value = "/student") public Object student(@RequestParam(name = "id") Integer id, Integer age, String name, HttpServletRequest request) {// //RequestParam模式不传会报错,Integer id模式不传则为空 System.out.println(request.getHeader("Connection")); System.out.println(request.getCookies()); for (Cookie cookie : request.getCookies()) { if ("myCookie".equals(cookie.getName())) { System.out.println(cookie.getValue()); } } System.out.println(name); Student student = new Student(); student.setId(id); student.setAge(age); return student; } @GetMapping(value = "/student/detail/{id}/{age}") public Object student1(@PathVariable("id") Integer id, @PathVariable("age") Integer age) { Map<String,Object> retMap = new HashMap<>(); retMap.put("id",id); retMap.put("age",age); System.out.println(retMap); return retMap; } // @RequestMapping(value = "/student/detail/{id}/{status}") @DeleteMapping(value = "/student/detail/{id}/{status}") public Object student2(@PathVariable("id") Integer id, @PathVariable("status") Integer status) { Map<String,Object> retMap = new HashMap<>(); retMap.put("id",id); retMap.put("status",status); return retMap; } @DeleteMapping(value = "/student/{id}/detail/{city}") public Object student3(@PathVariable("id") Integer id, @PathVariable("city") Integer city) { Map<String,Object> retMap = new HashMap<>(); retMap.put("id",id); retMap.put("city",city); return retMap; } @PostMapping(value = "/student/{id}") public void addStudent(@RequestBody Student student,@PathVariable("id") Integer id) { System.out.println("----------start------"); System.out.println(student.getName()); System.out.println(student); System.out.println(id); System.out.println("----------end------"); } @PostMapping(value = "/student2") public Object addStudent2(@RequestBody Student student) { System.out.println("----------start------"); System.out.println(student); System.out.println("----------end------"); return student; } @PostMapping(value = "/student3") public Object addStudent3(Student student) {// 不写@RequestBody相当于获取类的初始值 System.out.println("----------start------"); System.out.println(student); System.out.println("----------end------"); return student; } @PutMapping(value = "/student/{id}") public String updateStudent(@PathVariable("id") Integer id,@RequestBody Student student) { System.out.println(student); return "update Student ID:" +id; }}

April 4, 2023 · 2 min · jiezi

关于java:2023年适合自学Java学习路线图完整版

这里小千作为资深的教育培训机构,特意为大家整顿分享一套零根底自学Java学习路线图,此学习路线一共分为Java根底、数据库、Javaweb、企业级框架、散布式微服务架构、高手进阶、我的项目实战七大阶段,心愿能够帮忙到大家。 第一阶段:Java外围根底此阶段为入职java必备常识,必须牢牢把握,把根底砸实是学习的根基,会让前面的内容学习变得熟能生巧 1.Java设计模式Java程序员核心技术必备,设计模式,疾速通透! 2.强化编程-数据结构与算法学习常见的数据架构和算法,建设其良好的编程思维,造成本人的编程思维。把握各种算法,晋升本人的编程能力。把握根本的数据结构,加深对程序底层的了解。利用编程思维解决生存和工作中的各种问题。 第二阶段:数据库核心技术数据库技术是软件开发中的必备技能,咱们从数据库基本操作到把握数据库设计的能力,层层深刻学习数据库设计思维,一个软件我的项目的底层逻辑中,数据的存储构造是重中之重,因而,数据库技术也是面试中常被面试官拿来考查面试者的必用问题。 1.MySQL根底+进阶本阶段次要学习把握MySQL数据库 MySQL数据库设计、E-R图等 2.支流分库分表中间件从分库分表原理进行学习、sharding-jdbc实现逻辑、案例及线上环境配置,全方位理解把握sharding-jdbc这款支流分库分表中间件。 第三阶段:Javaweb核心技术JavaWeb核心技术:这块内容,咱们要围绕基于浏览器、服务器我的项目开发的全过程,因为将来大家从事的工作岗位中,90%以上的 Java 开发工作,都是基于这种模式,也称为 B/S模式开发。 1.Javaweb根底+实战针对具备JavaSE根底的同学,熟练掌握MySQL数据库的开发利用,把握数据库设计流程并能更具我的项目业务场景实现数据库设计;零碎把握HTML5、CSS3、JavaScript、AJAX、jQuery、BootStrap等web前端开发技术;纯熟应用Servlet、JSP动静网页技术进行Java web利用的性能开发;深刻了解和把握Java web技术栈的外围开发技术,晋升综合开发利用能力。 第四阶段:企业框架级技术此阶段为企业级服务端开发必备技能,优化web阶段内容,应答java开发中级岗位 1.项目管理-maven从我的项目为什么须要构建工具到我的项目仓库私服搭建。是入门Maven小白必备课程,以浅显易懂的语言、深入浅出的解说,带你走入Maven的世界,纯熟Maven的应用,从入门到精通。 2.项目管理-git包含版本治理的劣势、Git的根本应用、Git近程仓库、Git协同开发、Git分支治理、Git整合Idea等,学完将会全面把握Git的理论应用,帮忙你在企业团队协同开发中进步工作效率。 3.SSM框架:spring+SpringMVC+MyBatisSpring整合MyBatis我的项目开发;SpringMVC框架部署和配置,SprinGMVC框架全流程执行原理 ;ybatis配置和应用、Mybatis常见面试问题解析。 4.Spring全套详解(Ioc-AOP-整合MyBatis)包含Spring IoC、Spring AOP(CGLib、JDK动静代理)、Spring整合MyBatis,Spring事务管理等内容。 5.Mybatis框架(全程带练,源码解析)包含ORM概述、Mybatis概述、Mybatis增删查改、Mybatis配置文件详解、Mybatis关联映射、MyBatis动静SQL、Mybatis日志配置、Mybatis连接池、Mybatis缓存、Mybatis提早加载、Mybatis原理解析等。 6.SpringMVC(框架源码解析)包含SpringMVC的框架部署配置、创立控制器、前端申请控制器或者动态资源配置、控制器接收前端数据、并对前端申请作出响应等全流程全细节的解说。最初将会实现三大框架(Spring、SpringMVC、Mybatis)终极整合。 7.长久层开发框架-MybatisPLUSMybatisPlus教程(深入浅出,疾速上手),Mybatis-Plus带你高效开发WEB利用。 8.服务疾速开发技术-springboot基于官网提供的最新版本SpringBoot 2.7.1进行学习,笼罩机构及企业针对于springBoot所有的内容需要,围绕着外围根底、日志框架、SpringBoot与其余技术整合(如Redis Ecache Elasticsearch MQ Quarts....)等、源码的分析(搭建源码环境、运行的原理、内置tomcat、自定义starter等等)还有部署监控等内容。 9.SpringSecurity首先大家要学会Spring Security框架的根本用法,实现框架的根本配置。而后具体学习Security框架中的过滤器、认证形式、JWT的应用等内容。最初应用Spring Security+JWT的形式,做一个权限认证零碎的微服务项目。从单体环境下的权限认证,到微服务前后端分离式的权限零碎。 10.Java日志框架针对有Java根底的小伙伴,由浅入深具体学习每个知识点以及编程思维,帮忙小伙伴建设齐备的Java日志零碎常识体系以及高性能的日志框架选型。 第五阶段:散布式微服务架构此阶段把握当下热门服务框架,贴合Java开发发展趋势,可轻松应答Java互联网开发大部分岗位 1.微服务框架-Spring cloud通过本课程的学习,你将深刻理解微服务架构, 精通springcloud-alibaba各个组件的工作原理及其应用,吊打面试官,高薪拿offer。 2.分布式框架-Dubbo本知识点内容旨在深度剖析服务之间调用逻辑,从分析RPC底层原理开始,通过手写RPC框架,把握RPC实现逻辑。通过全方位介绍微服务RPC框架Dubbo,实现Dubbo在各实战场景中的利用。通过分析Dubbo源码,把握Dubbo的服务通信、负载平衡、SPI机制及服务治理的实现逻辑。 3.分布式框架-zookeeper通过本课程的学习你将具备:Zookeeper的底层数据存储逻辑 Zookeeper客户端的残缺操作流程 Zookeeper集群实战技能 分布式架构思维的疏导及建设。 4.TiDB数据库通过本课程的学习,你将具备:可能疾速部署TiDB测试集群;把握TiDB的外围个性;把握TiDB的命令及SQL操作;把握JDBC及SpringBoot整合TiDB;把握TiDB的外围分布式概念。 5.音讯队列-RabbitMQ本课程须要先学会RabbitMQ的根本装置和应用,再进行RabbitMQ的多种队列模式学习,理解每个队列模式的长处、利用场景及存在的问题,一环扣一环,大家须要晓得工作中改如何抉择应用哪一种队列模式。并分明Springboot中如何应用rabbitmq。 6.音讯队列-RocketMQRocketMQ在阿里巴巴电商环境下经验过了多年的技术系列,其性能和稳定性,在泛滥MQ中脱引而出。 本课程要理解RocketMQ的技术架构和部署架构,再通过RocketMQ从装置到应用的疾速体验。而后着重学习RocketMQ的集群模式、多种音讯实例,以及Springboot和Spring Cloud Stream如何整合RocketMQ。 7.ActiveMQ音讯队列课程从音讯队列概念、JMS基本概念开始学习,再逐渐联合Activemq代码实现音讯队列。把握好这些常识,不仅能够从容应对面试,也晋升了技术的深度。 8.分布式音讯-Kafka通过本套课程的学习,你将具备:Kafka根底概念及关键技术点,Kafka集群配置及外围参数,Kafka集群应答大并发、高可用场景的多维度优化计划,Kafka-eagle监控平台的应用。 9.微服务部署-Docker本节内容是次要针对微服务架构落地解决技术计划之一。通过学习Docker可能实现对:微服务监控告警架构、微服务自动化部署、微服务之日志收集与性能监控、微服务之自动化测试与品质治理等架构的落地技术实现。 10.分布式缓存-Redis是一个开源的应用ANSI C语言编写、反对网络、可基于内存亦可长久化的日志型、Key-Value数据库,并提供多种语言的API。 11.分布式搜寻-ElasticSearch本课程理解目前最风行的ElasticSearch全文检索框架, 体验PB级海量数据秒级搜寻,学习后的播种不仅仅是简略应用,还有实战内容, 将手把手带您一起实现京东搜寻性能的实现。 12.JUC 并发编程本套课程能够零碎残缺的帮忙小伙伴建设齐备的JUC并发编程常识体系。 第六阶段:高手进阶,技能深刻篇此阶段常识内容为丰盛把握各技术点的底层原理,可能实现各相似需要性能框架,晋升本身外围竞争力,应答大厂自研技术需要 1.Linux操作系统针对于Linux有零碎的学习,目标在与帮忙目前的java程序员学习Linux课程所碰到的一些窘境做了解说。 2.强化编程-JVM通过多维度案例介绍类加载到运行的整个JVM运行过程,把握JVM从对象创立到销毁的整个过程。通过剖析垃圾回收算法,把握各垃圾回收器的工作机制。 3.数据库强化-MySQLMySQL高级进阶课程,为面试和工作晋升必备课程。课程中以案例剖析的模式进行MySQL优化的深度剖析、以及介绍MySQL优化罕用剖析工具的应用。 4.数据库强化-Oracle理解应用Oracle 12g进行数据管理及开发利用的各方面技术。 5.搜寻技术-Lucene通过本套课程的学习,你将具备:1.把握全文检索应用场景及技术选型 2.可能应用Lucene编写出京东搜寻这样的性能 3.把握Lucene底层存储的逻辑构造和物理构造 4.把握索引常见的搜索算法 5.可能对全文检索底层优化(查问精准度, 查问效率)有独到的见解及思路。 ...

April 4, 2023 · 1 min · jiezi

关于java:算法从入门到精通选择排序

一、排序和算法 排序是算法中的一部分,也叫排序算法。算法个别用来解决数据,而数据的解决最好是要找到他们的法则,这个法则中有很大一部分就是要进行排序,所以须要有排序算法。本节解说的是抉择排序,从抉择排序开始意识排序的一些根底概念。之所以将抉择排序作为排序的入门,起因是抉择排序算法的逻辑最好了解。 二、抉择排序 2.1 抉择排序算法逻辑抉择排序是一种最简略的排序算法。其排序的逻辑如下:1、有一个待排序的数组A(以下简称A)。2、从A中找出最小的元素。3、将找到的最小元素跟数组A中第一个元素替换地位(如果最小元素就是第一个元素,则本人跟本人替换地位);如下图: (如上图,长方形高下代表数字的大小,找到最小的数字,跟第一个地位的数据进行替换)替换之后,后果如下图所示: 4、而后,在剩下的4个数字中再找到最小的那个数字,跟第2个地位的数字替换。如下图: 替换之后的后果如下如: 5、再在剩下的三个数字中,找到最小的那个数字跟第3个地位的数字替换地位。上图中剩下的三个数字中最小的就是第3个地位的数字,所以,它本人跟本人替换地位,就是不变。 同理第四个数字也是不变,第5个数字也是不变。(上图中例子第3、4、5个元素正好就是对应的排序,所以不变。如果不是对应的最小数字,同理替换地位就行。)以上就是抉择排序的算法逻辑,十分好了解。(如果有疑难的同学,欢送下方留言)。 2.2 抉择排序算法代码实现了解了抉择排序的逻辑之后,接下来通过java代码实现抉择排序算法。步骤如下: 1、找出最小的数字2、将最小的数字放到第一个地位3、将第一个地位的数字,放到本来是最小数字的地位。4、反复下面3个步骤抉择排序java代码如下:  /**  抉择排序 */ public static void algorithm4(){ //定义一个整数类型数组,用于排序的原始数据  int[] array={3,5,1,2,4};  //获取数组的大小 int length = array.length; //第一个循环用来遍历数组中的所有数字 for (int i = 0; i < length; i++) { //初始化一个变量,用来记录最小数字的下标。初始默认假如第一个数字就是最小数字 int minIndex = i; //第二个循环,通过比拟获取数组中最小的数字的下标。 for (int j = i+1; j < length ; j++) { //如果找到更小的数字, if (array[minIndex]>=array[j]) { //将minIndex变量的值批改为新的最小数字的下标。 minIndex = j; } }  //所有数字一个个比拟完结之后,就能确认那个数字最小了。 //将最小的数字替换到第一个地位,将第一个地位的数字放到最小数字原来的地位,就是一次替换。 int temp=array[i]; array[i]=array[minIndex]; array[minIndex]=temp; }  //将排序之后的数组打印进去。 //上面的输入是不计算工夫复杂度的,因为理论开发中这段输入代码会被删掉 for (int i = 0; i < length; i++) { System.out.print(array[i]+","); }   } 以上就是抉择排序的代码实现。学习了后面的工夫复杂度之后,大家能够计算一下抉择排序的工夫复杂度是多少呢? 2.3、抉择排序的工夫复杂度抉择排序总共循环了所少次?n+(n-1)+(n-2)+(n-3)+…+1上述这个表达式,反过来写就是1+2+3+4+5+…+n。高斯算法就是(n+1)n/2=(n^2+n)/2=1/2n^2+n/2。当n->∞时,利用极限思维1/2*n^2+n/2能够等于n^2,记作O(n^2),也就是抉择排序的工夫复杂度是O(n^2)。 总结抉择排序是一种简略的排序算法,实用于数据量较小的状况,因为依据工夫复杂度剖析,数据量越大,抉择排序所破费的工夫依照平方倍数增长,会十分慢。然而抉择排序也有它的劣势,抉择排序的劣势就是思维逻辑简略。抉择排序还有个特点,就是不管数组的程序是排好序或者是乱序的,抉择排序都须要破费一样的工夫来计算。 比方,利用抉择排序对数组{1,2,3,4,5}和数组{3,1,4,2,5}排序所破费的工夫是一样的。排序是算法中比拟重要的内容,从简略的动手,从易到难学习常见排序算法是一个比拟好的形式。如果有疑难的欢送大家留言探讨。

April 4, 2023 · 1 min · jiezi

关于java:选择排序底层原理详解

一. 搭建SpringBoot开发环境 咱们的Spring Security系列教程会基于SpringBoot环境,并且以案例迭代的形式进行开发,所以为了不便后续案例的编写,咱们先提前搭建一个SpringBoot环境的Web我的项目。 创立SpringBoot我的项目如各位对SpringBoot根底不相熟,请参考自己的SpringBoot系列教程:blog.csdn.net/syc000666/a…SpringBoot我的项目的具体创立过程如下图所示。1.1 创立一个基于Maven的Project我的项目。 1.2 设置项目名称和存储地位 增加我的项目依赖在pom.xml文件中,增加配置SpringBoot开发环境的依赖包。<properties> <java.version>1.8</java.version> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.2.5.RELEASE</spring-boot.version> <spring-platform.version>Cairo-SR3</spring-platform.version></properties><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--BOM(bill of materials):资料清单,用于解决jar包依赖的好办法--> <!--缘起:Spring当初已倒退成一个宏大体系。比方security、mvc等。如此一来,不同模块或者与内部进行集成时, 依赖解决就须要各自对应版本号。比方,较新spring与较老的quartz,它们集成就会遇到问题,给搭建和降级带来不便。 因而Spring IO Platform应运而生,只有我的项目中引入了它,内部集成时依赖关系无需版本号。--> <dependency> <groupId>io.spring.platform</groupId> <artifactId>platform-bom</artifactId> <version>${spring-platform.version}</version> <type>pom</type> <scope>import</scope> </dependency></dependencies></dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies><build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins></build><!--配置地方仓库--><repositories> <repository> <id>aliyun-repos</id> <url>https://maven.aliyun.com/repository/public</url> <snapshots> <enabled>false</enabled> </snapshots> </repository></repositories>复制代码增加完SpringBoot中次要的依赖包之后,咱们就能够在这个环境中进行Web我的项目开发了。 二. 创立第一个SpringSecurity我的项目咱们在下面的SpringBoot开发环境中,创立出第一个SpringSecurity模块,具体创立过程略(嘿嘿)。 增加模块中的pom依赖咱们在该module中,增加我的项目开发时必要的依赖包,次要是增加SpringSecurity的依赖包,在这里会完满体现SpringBoot中”约定大于配置“的思维哦。<dependencies><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency> <!--外围平安依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId></dependency> ...

April 4, 2023 · 1 min · jiezi

关于java:JAVA多线程并发编程避坑指南

作者:京东批发 肖朋伟 一、前言开发过程中,多线程的利用场景堪称非常宽泛,能够充分利用服务器资源,进步程序处理速度。咱们通常也会应用池化技术,去防止频繁创立和销毁线程。 本篇旨在基于编码标准、工作中积攒的研发教训等,整顿在多线程开发的过程中须要留神的局部,比方不思考线程池参数、线程平安、死锁等问题,将会存在潜在极大的危险。并且对其进行根因剖析,防止每天踩一坑,坑坑不一样。 二、多线程并发场景有哪些坑?1、“不正确的创立”线程池惯例来说,线程资源必须通过线程池提供,不容许在利用中自行显式创立线程,京东 JAVA 代码标准也明确示意 “线程资源必须通过线程池提供,不容许在利用中自行显式创立线程”,然而创立线程池的形式也有很多种,不能滥用。 常见创立线程池形式如:通过 JDK 提供的 ThreadPoolExecutor、ScheduledThreadPoolExecutor 以及 JDK 7 开始引入的 ForkJoinPool 创立,还有更不便的 Executors 类以及 spring 提供的 ThreadPoolTaskExecutor 等。其关系如下图: Executors 的 newFixedThreadPool、newScheduledThreadPool、newSingleThreadExecutor、newCachedThreadPool 办法在底层都是用的 ThreadPoolExecutor 实现的。尽管更加不便,但也减少了危险,如果不分明其相干实现,在特定场景可能导致很重大的问题,所以开发标准中,会严格禁用此类用法。它们的弊病如下: (1)FixedThreadPool 和 SingleThreadPool 容许的申请工作队列长度为 Integer.MAX_VALUE,可能会沉积大量的申请,从而导致 OOM。 (2)CachedThreadPool 和 ScheduledThreadPool 容许的创立线程数量为 Integer.MAX_VALUE,可能会创立大量的线程,从而导致 OOM。 2、线程池“参数设置不合理”下面提到了 工作队列 和 最大线程数的重要性,上面通过 ThreadPoolExecutor 介绍线程池其余外围参数,都应该依据场景合理配置,具体如下: 留神在设置工作队列时,须要思考有界和无界队列,应用有界队列时,留神线程池满了后,被回绝的工作如何解决。应用无界队列时,须要留神如果工作的提交速度大于线程池的处理速度,可能会导致内存溢出。 对于回绝策略,首先要明确的一点是“回绝策略的执行线程是提交工作的线程,而不是子线程”。JDK 的 ThreadPoolExecutor 提供了 4 种回绝策略: 对于自定义回绝策略,不同场景应抉择相应的回绝策略,抛开利用场景讲技术会显得红润,大家能够参考常见技术框架的解决形式: 相干拓展: 置信大多数京东开发者都遇到过,JSF 依赖服务触发回绝策略的景象,即抛出线程回绝异样。这是当 Provider的 业务线程池满了,无可用线程池的时候,会返回一个异样给 Consumer,告知 Consumer 该 Provider 线程池已耗尽。如图: ...

April 4, 2023 · 2 min · jiezi

关于java:IotLink版本跟新V1100

平台简介物联网是一套全副开源的疾速开发平台,毫无保留给集体及企业收费应用。 前端采纳Vue、Element UI。后端采纳Spring Boot、Spring Security、Redis & Jwt。权限认证应用Jwt,反对多终端认证零碎。反对加载动静权限菜单,多形式轻松权限管制。高效率开发,应用代码生成器能够一键生成前后端代码。 更新内容新增第三方接口 梦网新增第三方接口 腾宇

April 4, 2023 · 1 min · jiezi

关于java:centos7-安装jdk和maven

centos7 装置jdk1.81. 先看下服务器上有没有装置了jdk查看零碎是否自带jdkjava -version查看相干java文件rpm -qa | grep java2. 下载jdk1.8的安装包间接在官网下载即可https://www.oracle.com/cn/java/technologies/javase/javase8u21... 3. 上传到服务器上我这里是上传到/usr/local/java 目录下的, java是本人新建的目录4. 解压tar -zxvf jdk-8u221-linux-x64.tar.gz5. 配置零碎变量vi /etc/profile#java environmentexport JAVA_HOME=/usr/local/java/jdk1.8.0_221export PATH=$PATH:${JAVA_HOME}/bin 6. 让批改后的配置文件失效source /etc/profile7. 验证java -versioncentos7 装置maven1. 先看下服务器上有没有装置了maven查看零碎是否自带mavenmvn -v查看相干maven文件rpm -qa | grep maven2. 去官网下载maven的安装包http://maven.apache.org/download.cgi 3. 上传到服务器上我这里是上传到/usr/local/ 目录下的4. 解压tar -zxvf apache-maven-3.1.1-bin.tar.gz5. 改名mv apache-maven-3.1.1 maven6. 配置零碎变量vi /etc/profile#maven environmentexport MAVEN_HOME=/usr/local/mavenexport PATH=$PATH:$MAVEN_HOME/bin 7. 让批改后的配置文件失效source /etc/profile8. 验证mvn -v

April 3, 2023 · 1 min · jiezi

关于java:求求你别乱脱敏了MyBatis-插件-注解轻松实现数据脱敏So-easy

问题在我的项目中须要对用户敏感数据进行脱敏解决,例如身份号、手机号等信息进行加密再入库。 解决思路就是:一种最简略间接的形式,在所有波及数据敏感的查问到对插入时进行明码加解密办法二:有办法一到呈现对所有重大问题的影响,须要思考到问题的呈现,并且须要思考可能呈现的组员时增加数据的办法。最初决定采纳mybatis的插件在mybatis的SQL执行和后果填充操作上进行切入。下层业务调用不再须要思考数据的加敏同时也保障了数据的加解密Mybatis 插件原理Mybatis 的是通过拦截器实现的,Mabatis 反对对当事人进行拦挡 实现设置对参数中带有敏感参数字段的数据时进行加密对返回的后果进行解密解决依据不同的要求,咱们只须要对ParameterHandler和ResultSetHandler进行切入。 定义特定注解,在切入时须要查看字段中是否蕴含注解来是否加解密 加注解定义SensitiveData注解 import java.lang.annotation.*;/** * 该注解定义在类上 * 插件通过扫描类对象是否蕴含这个注解来决定是否持续扫描其中的字段注解 * 这个注解要配合EncryptTransaction注解 **/@Inherited@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface SensitiveData {}定义EncryptTransaction注解 import java.lang.annotation.*;/** * 该注解有两种应用形式 * ①:配合@SensitiveData加在类中的字段上 * ②:间接在Mapper中的办法参数上应用 **/@Documented@Inherited@Target({ElementType.FIELD, ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)public @interface EncryptTransaction {}加解密工具类解密 package sicnu.cs.ich.common.interceptor.transaction.service;public interface IDecryptUtil { /** * 解密 * * @param result resultType的实例 * @return T * @throws IllegalAccessException 字段不可拜访异样 */ <T> T decrypt(T result) throws IllegalAccessException;}加密接口 package sicnu.cs.ich.common.interceptor.transaction.service;import java.lang.reflect.Field;public interface IEncryptUtil { /** * 加密 * * @param declaredFields 加密字段 * @param paramsObject 对象 * @param <T> 入参类型 * @return 返回加密 * @throws IllegalAccessException 不可拜访 */ <T> T encrypt(Field[] declaredFields, T paramsObject) throws IllegalAccessException;}package sicnu.cs.ich.common.interceptor.transaction.service.impl;import org.springframework.stereotype.Component;import sicnu.cs.ich.api.common.annotations.transaction.EncryptTransaction;import sicnu.cs.ich.common.interceptor.transaction.service.IDecryptUtil;import sicnu.cs.ich.common.util.keyCryptor.DBAESUtil;import java.lang.reflect.Field;import java.util.Objects;@Componentpublic class DecryptImpl implements IDecryptUtil { /** * 解密 * * @param result resultType的实例 */ @Override public <T> T decrypt(T result) throws IllegalAccessException { //取出resultType的类 Class<?> resultClass = result.getClass(); Field[] declaredFields = resultClass.getDeclaredFields(); for (Field field : declaredFields) { //取出所有被DecryptTransaction注解的字段 EncryptTransaction encryptTransaction = field.getAnnotation(EncryptTransaction.class); if (!Objects.isNull(encryptTransaction)) { field.setAccessible(true); Object object = field.get(result); //String的解密 if (object instanceof String) { String value = (String) object; //对注解的字段进行逐个解密 try { field.set(result, DBAESUtil.decrypt(value)); } catch (Exception e) { e.printStackTrace(); } } } } return result; }}加密实现类 ...

April 3, 2023 · 5 min · jiezi

关于java:Java19新特性

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址 如果拜访不了Github,能够拜访gitee地址。 gitee地址 JDK 19 / Java 19 已正式公布。 新版本总共蕴含 7 个新的 JEP: 405:Record Patterns (Preview)422:Linux/RISC-V Port424:Foreign Function & Memory API (Preview)425:Virtual Threads (Preview)426:Vector API (Fourth Incubator)427:Pattern Matching for switch (Third Preview)428:Structured Concurrency (Incubator)405:记录模式 (Record Patterns) 进入预览阶段Record Patterns 可对 record 的值进行解构,Record patterns 和 Type patterns 通过嵌套可能实现弱小的、申明性的、可组合的数据导航和解决模式。 该个性目前处于预览阶段。 422:将 JDK 移植到 Linux/RISC-V 平台目前只反对 RISC-V 的 RV64GV 配置,它是一个通用的 64 位 ISA。未来会思考反对其余的 RISC-V 配置,例如通用的 32 位配置 (RV32G)。 424:内部函数和内存 API (Foreign Function & Memory API) 进入预览阶段Java 程序能够通过该 API 与 Java 运行时之外的代码和数据进行互操作。通过高效地调用内部函数(即 JVM 之外的代码)和平安地拜访内部内存(即不受 JVM 治理的内存),该 API 使 Java 程序可能调用本机库并解决本机数据,而不会像 JNI 那样危险和软弱。 ...

April 3, 2023 · 1 min · jiezi

关于java:数组的末尾添加替换删除任意位置插入获取

数组的开端增加、替换、删除、任意地位插入、获取数组类 import java.util.Arrays;/** * @author 23105 * @version 1.0 * @description: TODO * @date 1/4/2023 下午6:21 */public class ArrayCollection { // 用于存储数组的数据 private int[] arr; // 申明一个结构器 public ArrayCollection(){ // 先初始化数组长度为0 arr = new int[0]; } // 打印数组 public void show(){ System.out.println(Arrays.toString(arr)); } // 给数组开端增加一个新元素 public void addEle(int ele){ // 新建一个新数组,将旧数组的长度+1 int[] arrNew = new int[arr.length + 1]; // 遍历旧数组复制给新数组 for (int i = 0; i < arr.length; i++) { arrNew[i] = arr[i]; } // 将新增加的ele元素给新数组的最初一位 arrNew[arr.length] = ele; // 再将新数组arrNew赋值给旧数组arr arr = arrNew; } // 删除数组元素 public void delete(int index){ // 新建一个数组 int[] arrNew = new int[arr.length - 1]; // 先判断数组的索引是否越界 if (index < 0 || index > arr.length - 1) { throw new RuntimeException("数组下标越界"); } // 遍历新数组,将旧数组arr复制给新数组arrNew for (int i = 0; i < arrNew.length; i++) { if (index > i){ // 如果索引index大于i,失常赋值 arrNew[i] = arr[i]; }else { // 如果索引index小于i,将索引i+1,赋值给新数组 arrNew[i] = arr[i + 1]; } } // 再把新数组arrNew从新赋值给旧数组arr arr = arrNew; } // 获取数组某个地位的元素 public int get(int index){ return arr[index]; } // 向数组任意地位插入一个元素 public void insertEle(int index,int ele){ // 先判断数组的索引是否越界 if (index < 0 || index > arr.length - 1) { throw new RuntimeException("数组下标越界"); } // 新建一个数组 int[] arrNew = new int[arr.length + 1]; for (int i = 0; i < arr.length; i++) { if (index > i){ arrNew[i] = arr[i]; }else { arrNew[i + 1] = arr[i]; } } // 向index地位插入ele元素 arrNew[index] = ele; // 将新数组赋值arrNew给旧数组arr arr = arrNew; } // 替换指定地位的元素 public int replaceEle(int index,int ele){ // 判断index地位是否非法 // 先判断数组的索引是否越界 if (index < 0 || index > arr.length - 1) { throw new RuntimeException("数组下标越界"); } return arr[index] = ele; }}**测试与截图**/** ...

April 2, 2023 · 2 min · jiezi

关于java:完了良许直播中删库了……

大家好,我是良许。 明天跟大家聊个难堪的事,大家能够本着看热闹不嫌事大的心态来听我唠唠。 常常来我直播间(视频号+抖音)的小伙伴都晓得,我最近始终都在直播间手把手现场写 Shell 脚本。 就在前天早晨,我写 Shell 脚本的时候,不小心把当前目录下所有脚本(连同这个脚本自身)全副删除了,而且还全程直播了…… 这是我做直播到当初最大的一次直播事变啊。。 这个脚本的需要是这样的:把当前目录(蕴含子目录)下所有后缀为 ".sh" 的文件后缀变更为 ".shell",之后删除每个文件的第二行。 我先把正确的脚本贴出来给各位看官看看: #!/bin/bash ALL_SH_FILE=$(find . -type f -name "*.sh") for file in ${ALL_SH_FILE[*]} do     # filename=${file%.sh*}    filename=$(echo $file | awk -F'.sh' '{print $1}')     new_filename="${filename}.shell"     mv "$file" "$new_filename"     sed -i '2d' "$new_filename" done这个需要看起来蛮多的,但认真拆解一下,其实要求就上面这几个: 找到当前目录下所有以 .sh 结尾的文件;遍历这些文件,将后缀改为 .shell ;删除每个文件的第二行。咱们在写代码的时候,肯定不要焦急入手,先拆解一下,这样写起来就容易很多。上面就逐个解决这些需要。 需要1:找到当前目录下所有以 .sh 结尾的文件 找文件,很容易就想到 find 命令。 与 find 命令联合的选项无非就是:-type 、 -name 、 -size 、 -mtime ,其它的相对而言用得比拟少。在这里,很显著应用 -type 和 -name 。 要是连 find 命令都用不熟的小伙伴,连忙拍一拍文末的命令课。 ...

April 2, 2023 · 2 min · jiezi

关于java:关于private和protected的修饰符在实际使用中遇到的问题

访问控制修饰符Java中,能够应用拜访控制符来爱护对类、变量、办法和构造方法的拜访。Java 反对 4 种不同的拜访权限。 default (即默认,什么也不写): 在同一包内可见,不应用任何修饰符。应用对象:类、接口、变量、办法。 private : 在同一类内可见。应用对象:变量、办法。 留神:不能润饰类(外部类) public : 对所有类可见。应用对象:类、接口、变量、办法 protected : 对同一包内的类和所有子类可见。应用对象:变量、办法。 留神:不能润饰类(外部类)。摘自菜鸟教程本次程序的文件构造如下,是一个很简略的子类父类调用,其中Hanlder是父类,HanlderGo,HanlderHelp,HanlderBye皆继承自Hanlder然而在实习运行时却遇到了以下报错:这超长的报错属实是让我难绷,他们疯狂循环地跟我说,这些类,及而Handler父类的代码如下这里报错看似简单,实际上是咱们在子类中调用了父类中的对象Game而private只能在Handler类中应用game对象,要想在整个子类中都能应用game对象,就必须将其修饰符改为范畴更大的类型.

April 2, 2023 · 1 min · jiezi

关于java:Linux终端居然也可以做文件浏览器

大家好,我是良许。 在抖音上做直播曾经整整 5 个月了,我很骄傲我一路保持到了当初【笑脸】 最近我在做直播的时候,也开始学习鱼皮大佬,直播写代码。当然我不懂 Java 后端,因而就写写本人善于的 Shell 脚本。 然而,因为我是在 Linux 终端上写代码,没方法向观众敌人们展现一些图片或者 PDF 文档,影响了一些直播成果。 这几天在查阅材料的时候,终于找到了一个神器,性能上能够实现我的需要。这个神器就是—— ranger 。 1. 什么是 rangerranger 是一款轻量级并且性能非常弱小的 Linux 终端文件管理器,它跟 Vim 深度绑定。它不仅能够在终端间接查看文件内容,还能够疾速编辑文件。 ranger 的界面非常清新,能够显示目录的层次结构,能够容许你摸索文件系统、搜寻特定文件、切换目录等。 它一共由三列布局组成: 左栏:上一级目录中栏:当前目录内容右栏:所选文件或文件夹的预览除此之外, ranger 有哪些弱小的性能呢?次要有以下: 罕用文件操作(创立/批改权限/复制/删除);类 Vim 控制台和快捷键;切换目录和浏览文件系统的疾速办法;标签,书签,鼠标反对;视频缩略图预览;接下来具体介绍 ranger 的用法。 2. 装置 ranger因为 ranger 与 make、Git、Vim 所以在装置 ranger 之前,须要先装置好以上三个组件。 $ sudo apt install make git vim不过这三个工具作为程序员基本上都曾经装置好了。 ranger 简直曾经蕴含在所有 Linux 发行版,所以应用对应的包管理器基本上能够间接装置。 Debian/Ubuntu$ sudo apt install rangerCentOS/Fedora/RHELsudo yum install ranger3. ranger 的根本用法装置实现之后,只须要间接运行 ranger 这个命令就能够进入到 ranger 界面了。 ...

March 31, 2023 · 2 min · jiezi

关于java:一文快速入门任务调度框架Quartz

前言还不会 Quartz?如果你还没有接触过Quartz,那么你可能错过了一个很棒的任务调度框架!Quartz 提供了一种灵便、牢靠的形式来治理和执行定时工作,让咱们的定时工作更加优雅。本篇文章将为你介绍 Quartz 框架的外围概念、API 和实战技巧,让你轻松上手。也不必放心,作为过来人,我会把难懂的概念和术语解释分明,让你看完本篇文章后,就晓得该如何操作 Quartz。当然,本篇文章不免有不足之处,在此欢送大家指出。那废话少说,上面咱们开始吧! 什么是 Quartz?Quartz:https://github.com/quartz-scheduler/quartz 官网:http://www.quartz-scheduler.org/ Quartz 是一个功能丰富的开源任务调度框架(job scheduling library)。从最小的独立的 Java 应用程序到最大的电子商务系统,它简直都能够集成。Quartz 可用于创立简略或简单的调度,以执行数十、数百个甚至数万个工作;这些工作被定义为规范 Java 组件,这些组件能够执行你想让他做的任何事件。Quartz 调度程序包含许多企业级个性,例如反对 JTA 事务(Java Transaction API,简写 JTA)和集群。 留神:Job == 工作 JTA,即 Java Transaction API,JTA 容许应用程序执行分布式事务处理——在两个或多个网络计算机资源上拜访并且更新数据。 为什么学习 Quartz?定时工作间接用 Spring 提供的 @Schedule 不行吗?为什么还要学习 Quartz?有什么益处? 是的,一开始我也是这么想的,然而某些场景,单靠 @Schedule 你就实现不了了。 比方咱们须要对定时工作进行增删改查,是吧,@Schedule 就实现不了,你不可能每次新增一个定时工作都去手动改代码来增加吧。而 Quartz 就可能实现对工作的增删改查。当然,这只是 Quartz 的益处之一。 Quartz 的个性运行时环境 Quartz 能够嵌入另一个独立的应用程序中运行Quartz 能够在应用程序服务器(比方 Tomcat)中实例化,并参加 XA 事务(XA 是一个分布式事务协定)Quartz 能够作为一个独立程序运行(在其本人的Java虚拟机中),咱们通过 RMI(Remote Method Invocation,近程办法调用)应用它Quartz 能够实例化为一个独立程序集群(具备负载平衡和故障转移性能),用于执行工作工作的调度(Job Scheduling) 当一个触发器(Trigger)触发时,Job 就会被调度执行,触发器就是用来定义何时触发的(也能够说是一个执行打算),能够有以下任意的组合: 在一天中的某个工夫(毫秒)在一周中的某些日子在一个月的某些日子在一年中的某些日子反复特定次数反复直到特定的工夫/日期无限期反复以提早距离反复Job 由咱们本人去命名,也能够组织到命名组(named groups)中。Trigger 也能够被命名并分组,以便在调度器(Scheduler)中更容易地组织它们。 ...

March 31, 2023 · 10 min · jiezi

关于java:Java并发编程-Lock-Condition-ReentrantLock二

实现上一篇文章的未尽事宜: ReentrantLock的lock、unlock源码剖析Condition的await、signal源码剖析ReentrantLock#locklock办法最终是由sync实现的,偏心锁的sync是FairSync,非偏心锁是UnfairSync。 两者lock办法的区别是,偏心锁FairSync间接调用acquire(1)办法,非偏心锁UnfairSync则首先尝试取得锁资源(间接尝试批改锁状态)、获取不到才调用acquire(1)办法。 acquire办法由AQS实现。 AbstractQueuedSynchronizer#acquire首先调用tryAcquire办法尝试取得锁资源,如果获取不胜利的话,调用acquireQueued办法进入队列排队期待。 如果是通过acquireQueued办法通过排队获取到锁资源、并且办法返回true的话,阐明在线程排队期待锁资源的过程中收到了中断信号,然而因为线程处于挂起状态、尚未取得锁资源,不能对CLH队列做操作,所以须要等到获取到锁资源之后、再调用selfInterrupt()中断。 public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }上面咱们看一下tryAcquire及acquireQueued办法。 FairSync#tryAcquire以及UnFairSync#tryAcquire偏心锁与非偏心锁的tryAcquire办法的实现逻辑不同。 偏心锁FairSync#tryAcquire办法判断锁状态处于闲暇的话,首先调用hasQueuedPredecessors办法,判断以后CLH队列中是否存在比以后线程等待时间更久的线程,没有的话才尝试获取锁资源(CAS形式批改锁状态)。 非偏心锁UnFairSync#tryAcquire办法在判断锁处于闲暇状态的话,间接尝试获取锁资源(CAS形式批改锁状态)。 不论是FairSync还是UnFairSync的tryAcquire办法,如果判断锁资源是被以后线程独占,则能够间接再次获取锁资源,锁状态state在以后值的根底上加1。这也就是可重入锁的意思,同一线程能够屡次取得锁资源。 AbstractQueuedSynchronizer#acquireQueued在tryAcquire获取锁资源失败后,调用acquireQueued办法,办法名很好的阐明了办法的作用:通过排队取得锁资源。 办法的参数addWaiter(Node.EXCLUSIVE), arg),咱们先看一下这个办法。 private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } enq(node); return node; }代码其实很简略,首先将以后线程封装成Node,因为ReentrantLock是独占锁,所以Node的mode是独占。 ...

March 31, 2023 · 3 min · jiezi

关于java:阿里云阿里云OSS服务文件上传-后端签名

1. 概述当通过PostObject形式(HTML表单上传)向bucket上传文件时,如果bucket的权限为非公共读写时,则须要对上传操作进行签名验证。为了保障加密平安,签名个别都由后端进行,再传递给前端。签名所波及的字段有两个,一个是policy,一个是Signature。 2. policypolicy字段用于验证申请的合法性,如申请过期工夫、上传文件的大小等。还能够通过它对表单的其余字段进行肯定的限度。具体的规定能够自行参考文档。policy字段间接用字符串进行拼接生成即可。留神以下几点即可: 过期工夫以ISO8601 GMT工夫示意。$ + 字段名称指代须要限度的字段。留神相干字符增加本义符。UTF-8编码后进行Base64编码。3. SignatureSignature即签名字段。签名规定:以AccessSecretKey为key,应用Hmac-sha1对下面的policy进行加密,加密后果(byte[])间接进行Base64编码即可。 4. 示例//springboot@Componentpublic class AliyunOssUtils { @Value("${spring.aliyun.access-key-secret}") private String accessKeySecret; @Value("${spring.aliyun.oss-image-bucket}") private String imageBucket; //100s, 100mb public String getImagePolicy() throws UnsupportedEncodingException { //过期工夫100s long expirationEndTime = System.currentTimeMillis() + 100 * 1000; Date expiration = new Date(expirationEndTime); StringBuilder sb = new StringBuilder(); sb.append("{\"expiration\": \""); //工夫转ISO8601GTM的办法本人搜即可 sb.append(ISO8601.getISO8601(expiration)); sb.append("\","); sb.append("\"conditions\":[{\"bucket\":\""); sb.append(imageBucket); //上传限度100M sb.append("\"},[\"content-length-range\", 1, 104857600]]}"); String policy = sb.toString(); return Base64.getEncoder().encodeToString(policy.getBytes("UTF-8")); } public String signature(String policy) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException { Mac mac = Mac.getInstance("HmacSHA1"); SecretKey key = new SecretKeySpec(accessKeySecret.getBytes("UTF-8"), "HmacSHA1"); mac.init(key); mac.update(policy.getBytes("UTF-8")); byte[] res = mac.doFinal(); return Base64.getEncoder().encodeToString(res); }}

March 31, 2023 · 1 min · jiezi

关于java:通过Java实现Word转PDF

Word转为PDF是十分常见的一种格局转换。通过转换能够将文档以更为稳固的格局进行保留,防止别人随便批改格局和内容。其实Word转PDF并不难,除了间接转换外也能够通过编程的形式来实现。网上相干的教程分享也很多。明天想介绍一个Java Word组件——Free Spire.Doc for Java。通过它能够轻松实现Word转PDF,过程也非常简略容易上手。具体操作和代码请参考上面的内容。 导入jar包在进行操作之前,请先将jar包导入到Java程序中,有以下两种导入办法:办法一:如果您应用的是 maven,能够通过增加以下代码到我的项目的 pom.xml 文件中,将 jar文件导入到应用程序中。 <repositories> <repository> <id>com.e-iceblue</id> <name>e-iceblue</name> <url>https://repo.e-iceblue.cn/repository/maven-public/</url> </repository></repositories><dependencies> <dependency> <groupId>e-iceblue</groupId> <artifactId>spire.doc.free</artifactId> <version>5.2.0</version> </dependency></dependencies>办法二:如果没有应用 maven,则能够从此链接下载Free Spire.Doc for Java,找到lib文件夹下的Spire.doc.jar并进行解压;而后在IDEA中创立一个新我的项目,顺次点击“文件”(File),“我的项目构造”(Project Structure),“组件”(Modules),“依赖项”(Dependencies),再点击右方绿色“+”下的第一个选项“jar文件或门路”(JARs or Directories),找到解压后的Spire.doc.jar 文件,点击确认,将其导入到我的项目中。 具体办法首先实例化 Document 类的对象。调用 Document.loadFromFile() 办法加载 Word 文档。调用 Document.saveToFile() 办法将 Word 文档保留为 PDF 格局,指定保留门路。示例代码 import com.spire.doc.*;public class WordToPDF{ public static void main(String[] args) { //实例化Document类的对象 Document doc = new Document(); //加载Word doc.loadFromFile("sample.docx"); //保留为PDF格局 doc.saveToFile("result.pdf",FileFormat.PDF); }}

March 31, 2023 · 1 min · jiezi

关于java:又一款眼前一亮的Linux终端工具

大家好,我是良许。 最近二舅视频刷爆了全网,大家有没去看呢?强烈推荐大家观看一波,也就 11 分钟,保障会触动你的泪点。 不过明天不讲二舅哈,还是来聊聊技术。 明天给大家介绍一款最近发现的性能非常弱小,颜值十分高的一款终端工具。这个神器我是在其余公众号文章上看到的,但他们都没把它的弱小之处介绍明确,所以我本人体验一波后,再向大家分享本人的体验。 这款神器就是—— WindTerm ! 之前我也用过很多终端工具,比方 SecurCRT 、XShell、Putyy、MobaXterm。但我第一眼看到 WindTerm ,还是被深深吸引住了。 它是一款 C 语言开发的跨平台(Windows、MacOS、Linux) SSH 客户端,完全免费用于商业和非商业用途,没有限度。 所有公布的源代码(第三方目录除外)均在 Apache-2.0 许可条款下提供。 次要性能个性: 反对 SSH、Telnet、Tcp、Shell、Serial反对 SSH v2、Telnet、Raw Tcp、串行、Shell 协定。会话认证时反对 SSH 主动执行。反对 SSH ControlMaster。反对 SSH ProxyCommand 或 ProxyJump。反对 SSH 代理转发。反对应用明码、公钥、键盘交互、gssapi-with-mic 的 SSH 主动登录。反对 X11 转发。反对间接/本地端口转发、反向/近程端口转发和动静端口转发。反对 XModem、YModem 和 ZModem。集成 sftp、scp 客户端,反对下载、上传、删除、重命名、新建文件/目录等。集成本地文件管理器,反对挪动到、复制到、复制自、删除、重命名、新建文件/目录等。反对 Windows Cmd、PowerShell 和 Cmd、PowerShell 作为管理员。反对 Linux bash、zsh、powershell core 等。反对 MacOS bash、zsh、powershell core 等。联合我这几天的应用体验,跟大家分享一些着实让我震撼的个性。 以下动图来自作者博客,本想本人录制,后果录进去 gif 文件很大,有木有小伙伴教教我?一、WindTerm弱小之处1. 主动补全性能主动补全性能几乎是咱们程序员的福音!想想咱们在写代码的时候,主动补全性能节约了咱们多少工夫? WindTerm 竟然也自带主动补全性能,这我还是第一次在终端工具里见到。之前咱们敲命令,都通过一直敲击 Tab 键来补全命令,这下好了,都不必敲 Tab 键了。 ...

March 30, 2023 · 1 min · jiezi

关于java:Java-快速创建函数

Java 疾速创立函数System.out.println();---------> sout + tabpublic static void main(String[] args) {} ----------> psvm

March 30, 2023 · 1 min · jiezi

关于java:两条命令搞定-ChatGPT-API-的调用问题

自2022年11月30日 OpenAI 公布 ChatGPT 以来,尽管时有唱衰的声音呈现,但在OpenAI一直新陈代谢,陆续公布了OpenAPI、GPT-4、ChatGPT Plugins之后,仿佛让大家看到了一个聊天机器人往操作系统入口进军的升纬之路。 ChatGPT能被认为是操作系统级别的入口平台,那么必然会催生各行各业利用的从新入局。对此,作为一名开发者来说,面对这样的改革,应该尽早的去理解与实际,在蓝海里更容易找到一份本人的地位。目前DD晓得的就有不少小伙伴在基于其API做一些出海的利用。 最近,DD也花了不少工夫去钻研和体验了一些乏味的内容。比方:尝试跑了一些基于其API实现的类ChatGPT利用: 还有比方上面这个通过拖拽就能轻松调试和构建智能聊天利用的开源工具: 在这几天的一直尝试过程中,DD发现一个比拟麻烦的问题,就是这些利用都须要OpenAI的API Key。 作为开发者来说,置信不少小伙伴晓得如何获取了,这里就不细节说了,大家能够Google一下,有大量的材料。 这里具体说说另外一个问题:因为咱们本地调试、服务器部署等起因,在申请 https://api.openai.com 的时候,很容易造成IP凌乱,稍有不慎就有可能被封号。所以,咱们最好还是有一个稳固的位于国外的调用起源,这样日常开发调试就能更效率一些。 那么如何快捷不便的来搞定呢?上面就给大家分享一个利用阿里云函数计算(有大量收费试用额度)来实现的计划。 命令行部署筹备工作点击链接(https://t.aliyun.com/U/nb5Ka1),进入治理“控制台”,开明函数计算FC 装置最新版本的nodejs,不会的能够看官网:https://nodejs.org/执行命令装置Serverless Devs Toolnpm装置:$ npm install @serverless-devs/s -gyarn装置:$ yarn global add @serverless-devs/s通过该链接(https://usercenter.console.aliyun.com/#/manage/ak ),获取阿里云的AccessKey。肯定要把这里获取的AccessKey ID和AccessKey Secret记下来,上面马上要用。为Serverless Devs Tool配置阿里云的AccessKey$ s config add ? Please select a provider: Alibaba Cloud (alibaba) Refer to the document for alibaba key: http://config.devsapp.net/account/alibaba? AccessKeyID 此处填写AccessKeyID? AccessKeySecret 此处填写AccessKeySecret? Please create alias for key pair. If not, please enter to skip alibaba-accessAlias: alibaba-accessAccountID: 主动获取AccountIDAccessKeyID: 此处填写AccessKeyIDAccessKeySecret: 此处填写AccessKeySecret✔ Configuration successful两行命令实现部署在实现了下面的筹备工作之后,接下来咱们只须要两行命令即可实现代理服务的部署! ...

March 30, 2023 · 2 min · jiezi

关于java:Linux-服务器大量的-log-日志如何正确看日志快速定位错误你必须学会

针对大量log日志疾速定位谬误中央动静查看日志 tail -f catalina.ou从头关上日志文件 cat catalina.ou能够应用 >nanjiangtest.txt 输入某个新日志去查看 [root@yesky logs]# cat -n catalina.out |grep 717892466 >nanjiangtest.txttail/head简略命令应用:[root@yesky logs]# tail -n number catalina.out 查问日志尾部最初number行的日志 [root@yesky logs]# tail -n +number catalina.out 查问number行之后的所有日志 [root@yesky logs]# head -n number catalina.out 查问日志文件中的前number行日志 [root@yesky logs]# head -n -number catalina.out 查问日志文件除了最初number行的其余所有日志第一种形式(依据关键字查找出行号):用grep拿到的日志很少,咱们须要查看左近的日志。我是这样做的,首先: cat -n test.log | grep “关键词” 失去要害日志的行号 [root@yesky logs]# cat -n catalina.out |grep 71789246613230539 [11:07 17:47:11] INFO nanjiang:Edit Old Article:717892466-2020-11-07 17:47:1113230593 [11:07 17:47:15] INFO nanjiangSave Article ID IS:71789246613230595 717892466 article.getDisplayTime()1 = 2020-11-07 16:25:1113230596 717892466 article.getDisplayTime()2 = 2020-11-07 16:25:1113230601 [11:07 17:47:15] INFO 南江 10.10.10.39 edit article 717892466 编辑文章「cat -n catalina.out|tail -n +13230539|head -n 10」 ...

March 30, 2023 · 4 min · jiezi

关于java:对面的程序员赶紧看过来布隆过滤器又有新玩法了-博学谷狂野架构师

布隆过滤器作者: 博学谷狂野架构师GitHub:GitHub地址 (有我精心筹备的130本电子书PDF)只分享干货、不吹水,让咱们一起加油!什么是布隆过滤器布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器能够用于检索一个元素是否在一个汇合中。它的长处是空间效率和查问工夫都比个别的算法要好的多,毛病是有肯定的误识别率和删除艰难。布隆过滤器能够了解为一个不怎么准确的 set 构造,当你应用它的 contains 办法判断某个对象是否存在时,它可能会误判。然而布隆过滤器也不是特地不准确,只有参数设置的正当,它的精确度能够管制的绝对足够准确,只会有小小的误判概率。 当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就必定不存在。打个比方,当它说不意识你时,必定就不意识;当它说见过你时,可能基本就没见过面,不过因为你的脸跟它意识的人中某脸比拟类似 (某些熟脸的系数组合),所以误判以前见过你。套在下面的应用场景中,布隆过滤器能精确过滤掉那些曾经看过的内容,那些没有看过的新内容,它也会过滤掉极小一部分 (误判),然而绝大多数新内容它都能精确辨认。这样就能够齐全保障举荐给用户的内容都是无反复的。 布隆过滤器的原理其本质就是一个只蕴含0和1的数组。具体操作当一个元素被退出到汇合外面后,该元素通过K个Hash函数运算失去K个hash后的值,而后将K个值映射到这个位数组对应的地位,把对应地位的值设置为1。查问是否存在时,咱们就看对应的映射点地位如果全是1,他就很可能存在(跟hash函数的个数和hash函数的设计无关),如果有一个地位是0,那这个元素就肯定不存在。 首先须要初始化一个二进制的数组,长度设为 L,同时初始值全为 0 。当写入一个 A1=1000 的数据时,须要进行 H 次 hash 函数的运算(这里为 2 次);与 HashMap 有点相似,通过算出的 HashCode 与 L 取模后定位到 0、2 处,将该处的值设为 1。A2=2000 也是同理计算后将 4、7 地位设为 1。当有一个 B1=1000 须要判断是否存在时,也是做两次 Hash 运算,定位到 0、2 处,此时他们的值都为 1 ,所以认为 B1=1000 存在于汇合中。当有一个 B2=3000 时,也是同理。第一次 Hash 定位到 index=4 时,数组中的值为 1,所以再进行第二次 Hash 运算,后果定位到 index=5 的值为 0,所以认为 B2=3000 不存在于汇合中。整个的写入、查问的流程就是这样,汇总起来就是: 对写入的数据做 H 次 hash 运算定位到数组中的地位,同时将数据改为 1 。当有数据查问时也是同样的形式定位到数组中。一旦其中的有一位为 0 则认为数据必定不存在于汇合,否则数据可能存在于汇合中。布隆过滤器的特点只有返回数据不存在,则必定不存在。 ...

March 30, 2023 · 3 min · jiezi

关于java:京东二面线程池中的线程抛出了异常该如何处理大部分人都会答错

在理论开发中,咱们经常会用到线程池,但工作一旦提交到线程池之后,如果产生异样之后,怎么解决? 怎么获取到异样信息? 在理解这个问题之前,能够先看一下 线程池的源码解析,从源码中咱们晓得了线程池的提交形式:submit和execute的区别,接下来别离应用他们执行带有异样的工作!看后果是怎么样的! 咱们先用伪代码模仿一下线程池抛异样的场景: public class ThreadPoolException { public static void main(String[] args) { //创立一个线程池 ExecutorService executorService= Executors.newFixedThreadPool(1); //当线程池抛出异样后 submit无提醒,其余线程继续执行 executorService.submit(new task()); //当线程池抛出异样后 execute抛出异样,其余线程继续执行新工作 executorService.execute(new task()); }}//工作类class task implements Runnable{ @Override public void run() { System.out.println("进入了task办法!!!"); int i=1/0; }}运行后果: 能够看到:submit不打印异样信息,而execute则会打印异样信息!,submit的形式不打印异样信息,显然在生产中,是不可行的,因为咱们无奈保障线程中的工作永不异样,而如果应用submit的形式呈现了异样,间接如上写法,咱们将无奈获取到异样信息,做出对应的判断和解决,所以下一步须要晓得如何获取线程池抛出的异样! submit()想要获取异样信息就必须应用get()办法!! //当线程池抛出异样后 submit无提醒,其余线程继续执行Future<?> submit = executorService.submit(new task());submit.get();submit打印异样信息如下: 举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practice计划一应用 try -catchpublic class ThreadPoolException { public static void main(String[] args) { //创立一个线程池 ExecutorService executorService = Executors.newFixedThreadPool(1); //当线程池抛出异样后 submit无提醒,其余线程继续执行 executorService.submit(new task()); //当线程池抛出异样后 execute抛出异样,其余线程继续执行新工作 executorService.execute(new task()); }}// 工作类class task implements Runnable { @Override public void run() { try { System.out.println("进入了task办法!!!"); int i = 1 / 0; } catch (Exception e) { System.out.println("应用了try -catch 捕捉异样" + e); } }}打印后果: ...

March 30, 2023 · 4 min · jiezi

关于java:rocketONSstarter阿里云ONS消息服务的轻量级Spring-Boot-Starter

rocketONS-starter 介绍rocketONS-starter 是一个基于阿里云ONS音讯服务的轻量级Spring Boot Starter。它为您提供了一个简略高效的封装,使您可能疾速创立RocketMQ生产者和消费者,实现利用之间的消息传递。实用于高并发、高吞吐、低提早的分布式音讯场景。 软件架构rocketONS-starter 基于Spring的ApplicationContext容器治理,主动扫描consumer监听器,并注册启动消费者,用于接管和解决来自阿里云ONS服务散发的音讯。依据配置文件动态创建消费者和生产者,自定义消费者的启停开关,并主动序列化和解析音讯实体。同时,它还反对音讯过滤、程序音讯和延时音讯等高级性能,满足不同场景的需要。 次要特点简略易用:提供简洁的配置和API,疾速上手,轻松实现音讯生产和生产。高性能:基于阿里云ONS音讯服务,享受高并发、高吞吐、低提早的分布式音讯服务。弹性扩大:依据业务需要自在增加消费者和生产者,实现弹性扩大。高级性能反对:反对音讯过滤、程序音讯和延时音讯等高级性能,满足不同场景的需要。装置将以下依赖增加到您的我的项目中: <dependency> <groupId>io.gitee.zhucan123</groupId> <artifactId>rocket-ons-spring-boot-starter</artifactId> <version>1.0.8</version></dependency>应用阐明1. 将配置增加到我的项目中rocket: address: http://xxxx secretKey: xxxx accessKey: xxxx topic: xxxx groupSuffix: GID_ enable: true delay: 1000参数名类型是否必填默认值形容accessKeyString是-用于身份认证的AccessKeyId,创立于阿里云账号治理控制台。secretKeyString是-用于身份认证的AccessKeySecret,创立于阿里云账号治理控制台。addressString是-设置TCP协定接入点。groupSuffixString否GID_控制台创立的Group ID的前缀,通常以"GID_"结尾。topicString是-当生产者未指定topic时应用的默认绑定topic。delayInteger否1000音讯发送提早毫秒数。enableBoolean否true是否启用starter。2. 在主程序中启用rocketONS-starter@EnableRocketONSpublic class App { public static void main(String[] args) { SpringApplication.run(App.class, args); }}3. 示例代码:应用consumer@ConsumerListener(tags = "msg_tag", consumers = 2)@OnsConfiguration(topic = "topic-example", group = "GID_${example.group}")public class ExampleConsumerListener implements RocketListener<MessageData> { @Override public Action consume(Message message, MessageData messageBody, ConsumeContext consumeContext) { // 解决业务逻辑 return Action.CommitMessage; }}@OnsConfiguration:注册成一个Spring容器,并设置消费者绑定的topic和group。可设置固定值,也可应用${propertiesKey}的形式读取配置文件中的配置。@ConsumerListener:标识这是一个ONS音讯消费者监听器。能够设置tags来进行音讯过滤,设置consumers来指定消费者线程数。4. 示例代码:应用producer@Servicepublic class ExampleProducerService { @Autowired private RocketMQTemplate rocketMQTemplate; public void sendMessage(MessageData messageData) { rocketMQTemplate.syncSend("topic-example:msg_tag", messageData); }}通过注入RocketMQTemplate,应用syncSend办法同步发送音讯。办法参数中的字符串格局为topic:tag,示意发送到指定topic并设置音讯tag。 ...

March 30, 2023 · 2 min · jiezi

关于java:java实现布隆过滤器

什么是布隆过滤器布隆过滤器(Bloom Filter)是1970年由布隆提出来的。 它实际上是由一个很长的二进制数组+一系列hash算法映射函数,用于判断一个元素是否存在于汇合中。布隆过滤器能够用于检索一个元素是否在一个汇合中。它的长处是空间效率和查问工夫都比个别的算法要好的多,毛病是有肯定的误识别率和删除艰难。场景假如有10亿条手机号,而后判断某条手机号是否在列表内? mysql能够吗?失常状况下,如果数据量不大,咱们能够思考应用mysql存储。将所有数据存储到数据库,而后每次去库里查问判断是否存在。然而如果数据量太大,超过千万,mysql查问效率是很低的,特地耗费性能。 HashSet能够吗咱们能够把数据放入HashSet中,利用HashSet人造的去重性,查问只须要调用contains办法即可,然而hashset是寄存在内存中的,数据量过大内存间接oom了。 布隆过滤器特点插入和查问效率高,占用空间少,然而返回的后果是不确定的。一个元素如果判断为存在的时候,它不肯定真的存在。然而如果判断一个元素不存在,那么它肯定是不存在的。布隆过滤器能够增加元素,然而肯定不能删除元素,会导致误判率减少。布隆过滤器原理布隆过滤器其实就是是一个BIT数组,通过一系列hash算法映射出对应的hash,而后将hash对应的数组下标地位改为1。查问时就是对数据在进行一系列hash算法失去下标,从BIT数组里取数据如如果是1 则阐明数据有可能存在,如果是0 阐明肯定不存在为什么会有误差率咱们晓得布隆过滤器其实是对数据做hash,那么不论用什么算法,都有可能两条不同的数据生成的hash确是雷同的,也就是咱们常说的hash抵触。 首先插入一条数据: 好好学技术 再插入一条数据: 这是如果查问一条数据,假如他的hash下标曾经标为1了,那么布隆过滤器就会认为他存在 常见应用场景缓存穿透 java实现布隆过滤器package com.fandf.test.redis;import java.util.BitSet;/** * java布隆过滤器 * * @author fandongfeng */public class MyBloomFilter { /** * 位数组大小 */ private static final int DEFAULT_SIZE = 2 << 24; /** * 通过这个数组创立多个Hash函数 */ private static final int[] SEEDS = new int[]{4, 8, 16, 32, 64, 128, 256}; /** * 初始化位数组,数组中的元素只能是 0 或者 1 */ private final BitSet bits = new BitSet(DEFAULT_SIZE); /** * Hash函数数组 */ private final MyHash[] myHashes = new MyHash[SEEDS.length]; /** * 初始化多个蕴含 Hash 函数的类数组,每个类中的 Hash 函数都不一样 */ public MyBloomFilter() { // 初始化多个不同的 Hash 函数 for (int i = 0; i < SEEDS.length; i++) { myHashes[i] = new MyHash(DEFAULT_SIZE, SEEDS[i]); } } /** * 增加元素到位数组 */ public void add(Object value) { for (MyHash myHash : myHashes) { bits.set(myHash.hash(value), true); } } /** * 判断指定元素是否存在于位数组 */ public boolean contains(Object value) { boolean result = true; for (MyHash myHash : myHashes) { result = result && bits.get(myHash.hash(value)); } return result; } /** * 自定义 Hash 函数 */ private class MyHash { private int cap; private int seed; MyHash(int cap, int seed) { this.cap = cap; this.seed = seed; } /** * 计算 Hash 值 */ int hash(Object obj) { return (obj == null) ? 0 : Math.abs(seed * (cap - 1) & (obj.hashCode() ^ (obj.hashCode() >>> 16))); } } public static void main(String[] args) { String str = "好好学技术"; MyBloomFilter myBloomFilter = new MyBloomFilter(); System.out.println("str是否存在:" + myBloomFilter.contains(str)); myBloomFilter.add(str); System.out.println("str是否存在:" + myBloomFilter.contains(str)); }}Guava实现布隆过滤器引入依赖 ...

March 30, 2023 · 2 min · jiezi

关于java:Java高频面试题2023最新整理

Java的特点Java是一门面向对象的编程语言。面向对象和面向过程的区别参考下一个问题。 Java具备平台独立性和移植性。 Java有一句口号:Write once, run anywhere,一次编写、到处运行。这也是Java的魅力所在。而实现这种个性的正是Java虚拟机JVM。已编译的Java程序能够在任何带有JVM的平台上运行。你能够在windows平台编写代码,而后拿到linux上运行。只有你在编写完代码后,将代码编译成.class文件,再把class文件打成Java包,这个jar包就能够在不同的平台上运行了。Java具备稳健性。 Java是一个强类型语言,它容许扩大编译时查看潜在类型不匹配问题的性能。Java要求显式的办法申明,它不反对C格调的隐式申明。这些严格的要求保障编译程序能捕获调用谬误,这就导致更牢靠的程序。异样解决是Java中使得程序更持重的另一个特色。异样是某种相似于谬误的异样条件呈现的信号。应用try/catch/finally语句,程序员能够找到出错的解决代码,这就简化了出错解决和复原的工作。Java是如何实现跨平台的?Java是通过JVM(Java虚拟机)实现跨平台的。 JVM能够了解成一个软件,不同的平台有不同的版本。咱们编写的Java代码,编译后会生成.class 文件(字节码文件)。Java虚拟机就是负责将字节码文件翻译成特定平台下的机器码,通过JVM翻译成机器码之后能力运行。不同平台下编译生成的字节码是一样的,然而由JVM翻译成的机器码却不一样。 只有在不同平台上装置对应的JVM,就能够运行字节码文件,运行咱们编写的Java程序。 因而,运行Java程序必须有JVM的反对,因为编译的后果不是机器码,必须要通过JVM的翻译能力执行。 Java 与 C++ 的区别Java 是纯正的面向对象语言,所有的对象都继承自 java.lang.Object,C++ 兼容 C ,岂但反对面向对象也反对面向过程。Java 通过虚拟机从而实现跨平台个性, C++ 依赖于特定的平台。Java 没有指针,它的援用能够了解为平安指针,而 C++ 具备和 C 一样的指针。Java 反对主动垃圾回收,而 C++ 须要手动回收。Java 不反对多重继承,只能通过实现多个接口来达到雷同目标,而 C++ 反对多重继承。JDK/JRE/JVM三者的关系JVM 英文名称(Java Virtual Machine),就是咱们耳熟能详的 Java 虚拟机。Java 可能跨平台运行的外围在于 JVM 。 本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/Java-learning 所有的java程序会首先被编译为.class的类文件,这品种文件能够在虚拟机上执行。也就是说class文件并不间接与机器的操作系统交互,而是通过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地零碎执行。 针对不同的零碎有不同的 jvm 实现,有 Linux 版本的 jvm 实现,也有Windows 版本的 jvm 实现,然而同一段代码在编译后的字节码是一样的。这就是Java可能跨平台,实现一次编写,多处运行的起因所在。 JRE 英文名称(Java Runtime Environment),就是Java 运行时环境。咱们编写的Java程序必须要在JRE能力运行。它次要蕴含两个局部,JVM 和 Java 外围类库。 JRE是Java的运行环境,并不是一个开发环境,所以没有蕴含任何开发工具,如编译器和调试器等。 如果你只是想运行Java程序,而不是开发Java程序的话,那么你只须要装置JRE即可。 JDK 英文名称(Java Development Kit),就是 Java 开发工具包 ...

March 30, 2023 · 10 min · jiezi

关于java:Java之基础

1、HashMap解决hash抵触,链表法,红黑树和链表互相切换key是能够容许为null的,在Node节点下标为0处 替换的原理 : 两个hash值必须要相当,而后判断 (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) jdk8之后的亮点:1、hash抵触,应用高16和低16异或,使得hash数据分布更加平均,而后再与length-1相 & ,jdk1.7是间接获得hash & length -12、2的n次方,就能够保障说,(n - 1) & length,能够保障就是hash % 数组.length取模的一样的成果3、扩容:2倍容量进行扩容,jdk8不会像jdk7那样齐全hash一遍,jdk8扩容结束只能在原来index处,或者index + length 处 jdk1.7扩容死循环都是头插入方式惹的祸,比方 : k1 -> k2 -> k3,线程1和线程2同时要扩容,线程1一下子做完了,k3 -> k2 -> k1,线程2 苏醒过来,k1 -> k2(之前的),就造成环了 jdk1.8尾插入法 2、ConcurrentHashMapjdk1.7 ConcurrentHashMap由Segment数组构造和HashEntry数组组成。Segment是一种可重入锁,是一种数据和链表的构造,一个Segment中蕴含一个HashEntry数组,每个HashEntry又是一个链表构造ConcurrentHashMap 的扩容是仅仅和每个Segment元素中HashEntry数组的长度无关,但须要扩容时,只扩容以后Segment中HashEntry数组即可。也就是说ConcurrentHashMap中Segment[]数组的长度是在初始化的时候就确定了,前面扩容不会扭转这个长度所以说,针对jdk1.7来说,锁的并发度是不能扩容的 jdk1.8 勾销了segment数组,间接用table保留数据,锁的粒度更小,并发管制应用 synchronized + CAS来操作(如果Node<K,V>[] tab上没有数据就通过CAS设置数据),如果有要进行数据插入或者更新,加synchronized操作 3、解决并发问题的办法有哪些?无锁 : 局部变量(每个线程的工作内存中)、不可变对象、ThreadLocal(每个线程一个Map,Map key是以后实例对象,value是本人设置的值)、CAS(内存地址V,旧值预期值A,要批改的值B),当V==A的时候,V才能够批改为B,在Java中的实现则通常是指是以Atomic为前缀的一系列类,都采纳了CAS存在一个Unsafe实例,Unsafe类体用硬件级别的原子操作,问题:ABA(AtomicStampedReference记录版本)、循环工夫长开销大、只能保障一个共享变量的原子操作(AtomicReference)有锁 : Synchronized和ReentrantLock都是采纳了乐观锁的策略。Synchronized是通过语言层面来实现,ReentrantLock是通过编程形式实现4、共享数据操作如果一个线程在读取,一个线程在写,有相似如下操作就会有问题 : TaskInstance taskInstance = taskInstanceCache.get(taskInstanceId);taskInstance.setState(ExecutionStatus.of(status));taskInstance.setEndTime(endTime); 怎么办呢?间接taskInstanceCache.put(taskInstance);即可,因为这操作是原子性的 ...

March 29, 2023 · 2 min · jiezi

关于java:2023年找工作的心酸历程

点右上角加星标,江湖要事早晓得 前几天在脉脉上看到一个热议话题“23年找工作的心酸历程” 大家都晓得近几年互联网大环境不好,找工作变得越来越卷了、 就算是BAT这种大厂进去的,也不见得就有多好找工作,可想而知,如果你的背景和能力不是特地强,很有可能练简历关都过不了。 <figure> </figure> 特地是工作工夫久的老程序员,总包可能较高,相比其余刚毕业的小年老,更加不受企业待见。不晓得各位有没有这种感觉,这两年企业给的薪资涨幅广泛偏低,HR对立的口径便是一句话:你也晓得,这两年大环境不好,失常也只能给到平薪,涨幅10%-20%曾经是很多的了。 换在前几年,这样的公司可能要被拿进去吐槽,然而放在最近这几年,大家也都见怪不怪了。就连以前一些动辄50%-100%涨幅的公司,譬如某多多,当初也最多也只是十分激进地给到30%-50%。 <figure> </figure> 毕业几年后,对于校招的敏感度升高了不少,不晓得各位还在参加校招的读者们,对于这几年的校招有什么感想。 之前咱们团队也来了几个校招的新同学,感觉还是很优良的。将来的趋势是不是会越来越卷尚未可知,然而卷进去的人也越来越优良了,对于前辈们来说也是一种压力。 <figure> </figure> 另一方面,工作城市对于找工作来说也是很重要的。前两年我还在杭州的时候,有段时间在看里面的机会,感觉放眼望去,杭州全都是阿里系的公司,不能说全部都是,只能说多多少少都带着点阿里的影子。除了薪资给不到阿里的价格,其余方面倒是都学得明明白白的,一点不含糊。 尽管说杭州近几年也陆续搬来了很多大厂,比方字节,滴滴,百度等等,然而总体来说还是阿里系的半壁江山,想在这个城市找一个不卷躺平的公司,难度是要略微大一点的。相比之下,北上广深倒是显得更加多元化了一点。 北京我也是呆过一年的,广深我没有在那里工作过,也就不好做评估了。不过这两年在上海的工作体验的确要比杭州好一点,加班要少很多,当然了,这可能也是公司的起因。前几年大厂们纷纷开始缩小加班,推广双休,bat和字节也是首当其冲,我那会前脚刚从阿里来到,减负的政策就进去了,也不晓得这两年落实的如何了? <figure> </figure> <figure> </figure> 覆巢之下,安有完卵。在这种行情下,先保住本人的饭碗是最重要的。 除此之外,面对寒冬,何以解忧?唯有晋升本人。 【此处应该插入一则广告】 然而并没有。说了这么多,还是须要做一点理论的事件的。 最近有几件事要提上日程了了 1、从新开始写原创 恰逢金三银四面试季,面经和干货是刚需,我会多筹备点这方面的内容。 我打算把写作这件事件常态化,在有稳固的创作工序之前,我可能不会进行日更,一方面也是为了保证质量,另一方也是心愿可能满足大部分读者的要求。如果数据太差,那么就阐明读者并不喜爱这一类型的文章,咱们做技术的还是要以数据谈话。如果你喜爱的话,心愿点赞在看,这样能够让更多的人看到这篇文章。 2、保护JavaTutorial和集体网站 我有一个专一于Java面试的github https://github.com/h2pl/JavaTutorial 但曾经两年没有更新了,很多旧内容可能过期,新内容也还没来得及加上。因而我会从新去保护和重构这个github。 集体网站也会同步进行更新,相比于github,集体网站除了提供面试指南外,也会有更多其余的内容,目前我的老网站域名曾经生效了,昨天我刚申请了新的域名,后续如果弄好了我也会第一工夫告诉大家。 3、组建新的Java社群 老读者可能晓得我以前保护了很多群,起初因为保护群的微信被封,导致这几个群曾经没有方法保护,这也是十分惋惜的一件事。因而最近也须要把这件事从新做起来,心愿让各位Java技术人一起交流经验和技术。 家喻户晓的阿里文化有浓厚的武侠情节,阿里的会议室命名也都是出自武侠著述中的武林圣地, "光明顶"、"达摩院"、"罗汉堂"、"聚贤庄"、"半山亭"、"侠客岛"、"黑木崖"、"摩天崖"、"百花谷"等等。正好和咱们的“Java技术江湖”井水不犯河水。 作为前阿里人,我决定组建新Java社群也会以这样的形式命名。第一个群就取名为“桃花岛”好了,据说是马云办公室的名称。加群形式还是老规矩,微信私聊我,回复”加群,既然是第一个群,那么咱们就尽量到标杆作用,进群后还请按群布告的要求批改名片,留神恪守群规。 <figure> </figure> 明天就先说到这里了。 江湖再见,今天见。微信公众号【程序员黄小斜】作者是前蚂蚁金服Java工程师,专一分享Java技术干货和求职成长心得,不限于BAT面试,算法、计算机根底、数据库、分布式、spring全家桶、微服务、高并发、JVM、Docker容器,ELK、大数据等。关注后回复【book】支付精选20本Java面试必备精品电子书。

March 29, 2023 · 1 min · jiezi

关于java:ElasticSearch还能性能调优涨见识涨见识了

ElasticSearch 性能调优 作者: 博学谷狂野架构师GitHub地址:GitHub地址 (有咱们精心筹备的130本电子书PDF)概述性能优化是个涉及面十分广的问题,不同的环境,不同的业务场景可能会存在不同的优化计划,本文只对一些相干的知识点做简略的总结,具体计划能够依据场景自行尝试。 配置文件调优通过elasticsearch.yml配置文件调优内存锁定容许 JVM 锁住内存,禁止操作系统替换进来因为JVM产生swap替换会导致极大升高ES的性能,为了避免ES产生内存替换,咱们能够通过锁定内存来实现,这将极大进步查问性能,但同时可能造成OOM,须要对应做好资源监控,必要的时候进行干涉。 批改ES配置批改ES的配置文件elasticsearch.yml,设置bootstrap.memory_lock为trueCOPY#集群名称cluster.name: elastic#以后该节点的名称node.name: node-3#是不是有资格竞选主节点node.master: true#是否存储数据node.data: true#最大集群节点数node.max_local_storage_nodes: 3#给以后节点自定义属性(能够省略)#node.attr.rack: r1#数据存档地位path.data: /usr/share/elasticsearch/data#日志寄存地位path.logs: /usr/share/elasticsearch/log#是否开启时锁定内存(默认为是)#bootstrap.memory_lock: true#设置网关地址,我是被这个坑死了,这个地址我原先填写了本人的理论物理IP地址,#而后启动始终报有效的IP地址,无奈注入9300端口,这里只须要填写0.0.0.0network.host: 0.0.0.0#设置映射端口http.port: 9200#外部节点之间沟通端口transport.tcp.port: 9300#集群发现默认值为127.0.0.1:9300,如果要在其余主机上造成蕴含节点的群集,如果搭建集群则须要填写#es7.x 之后新增的配置,写入候选主节点的设施地址,在开启服务后能够被选为主节点,也就是说把所有的节点都写上discovery.seed_hosts: ["node-1","node-2","node-3"]#当你在搭建集群的时候,选出合格的节点集群,有些人说的太官网了,#其实就是,让你抉择比拟好的几个节点,在你节点启动时,在这些节点当选一个做领导者,#如果你不设置呢,elasticsearch就会本人选举,这里咱们把三个节点都写上cluster.initial_master_nodes: ["node-1","node-2","node-3"]#在群集齐全重新启动后阻止初始复原,直到启动N个节点#简略点说在集群启动后,至多复活多少个节点以上,那么这个服务才能够被应用,否则不能够被应用,gateway.recover_after_nodes: 2#删除索引是是否须要显示其名称,默认为显示#action.destructive_requires_name: true# 容许内存锁定,进步ES性能bootstrap.memory_lock: true批改JVM配置批改jvm.options,通常设置-Xms和-Xmx的的值为“物理内存大小的一半和32G的较小值”这是因为,es内核应用lucene,lucene自身是独自占用内存的,并且占用的还不少,官网倡议设置es内存,大小为物理内存的一半,剩下的一半留给lucene COPY-Xms2g-Xmx2g敞开操作系统的swap长期敞开COPYsudo swapoff -a 永恒敞开正文掉或删除所有swap相干的内容COPYvi /etc/fstab 批改文件描述符批改/etc/security/limits.conf,设置memlock为unlimitedCOPYelk hard memlock unlimitedelk soft memlock unlimited批改系统配置设置虚拟内存批改/etc/systemd/system.conf,设置vm.max_map_count为一个较大的值COPYvm.max_map_count=10240000批改文件下限批改/etc/systemd/system.conf,设置DefaultLimitNOFILE,DefaultLimitNPROC,DefaultLimitMEMLOCK为一个较大值,或者不限定COPYDefaultLimitNOFILE=100000DefaultLimitNPROC=100000DefaultLimitMEMLOCK=infinity重启ES服务发现优化Elasticsearch 默认被配置为应用单播发现,以避免节点无心中退出集群组播发现应该永远不被应用在生产环境了,否则你失去的后果就是一个节点意外的退出到了你的生产环境,仅仅是因为他们收到了一个谬误的组播信号,ES是一个P2P类型的分布式系统,应用gossip协定,集群的任意申请都能够发送到集群的任一节点,而后es外部会找到须要转发的节点,并且与之进行通信,在es1.x的版本,es默认是开启组播,启动es之后,能够疾速将局域网内集群名称,默认端口的雷同实例退出到一个大的集群,后续再es2.x之后,都调整成了单播,防止平安问题和网络风暴; 单播discovery.zen.ping.unicast.hosts,倡议写入集群内所有的节点及端口,如果新实例退出集群,新实例只须要写入以后集群的实例,即可主动退出到以后集群,之后再解决原实例的配置即可,新实例退出集群,不须要重启原有实例; 节点zen相干配置:discovery.zen.ping_timeout:判断master选举过程中,发现其余node存活的超时设置,次要影响选举的耗时,参数仅在退出或者选举 master 主节点的时候才起作用discovery.zen.join_timeout:节点确定退出到集群中,向主节点发送退出申请的超时工夫,默认为3sdiscovery.zen.minimum_master_nodes:参加master选举的最小节点数,当集群可能被选为master的节点数量小于最小数量时,集群将无奈失常选举。 故障检测( fault detection )故障检测状况以下两种状况下回进行故障检测COPY* 第一种是由master向集群的所有其余节点发动ping,验证节点是否处于活动状态* 第二种是:集群每个节点向master发动ping,判断master是否存活,是否须要发动选举配置形式故障检测须要配置以下设置应用discovery.zen.fd.ping_interval :节点被ping的频率,默认为1s。discovery.zen.fd.ping_timeout 期待ping响应的工夫,默认为 30s,运行的集群中,master 检测所有节点,以及节点检测 master 是否失常。discovery.zen.fd.ping_retries ping失败/超时多少导致节点被视为失败,默认为3。队列数量优化不倡议自觉加大es的队列数量,要依据理论状况来进行调整如果是偶发的因为数据突增,导致队列阻塞,加大队列size能够应用内存来缓存数据,如果是持续性的数据阻塞在队列,加大队列size除了加大内存占用,并不能无效进步数据写入速率,反而可能加大es宕机时候,在内存中可能失落的上数据量。 查看线程池状况通过以下能够查看线程池的状况,哪些状况下,加大队列size呢?COPYGET /_cat/thread_pool 察看api中返回的queue和rejected,如果的确存在队列回绝或者是继续的queue,能够酌情调整队列size。 内存应用配置熔断限额设置indices的内存熔断相干参数,依据理论状况进行调整,避免写入或查问压力过高导致OOMindices.breaker.total.limit: 50%,集群级别的断路器,默认为jvm堆的70%indices.breaker.request.limit: 10%,单个request的断路器限度,默认为jvm堆的60%indices.breaker.fielddata.limit: 10%,fielddata breaker限度,默认为jvm堆的60%。配置缓存依据理论状况调整查问占用cache,防止查问cache占用过多的jvm内存,参数为动态的,须要在每个数据节点配置indices.queries.cache.size: 5%,管制过滤器缓存的内存大小,默认为10%,承受百分比值,5%或者准确值,例如512mb。创立分片优化如果集群规模较大,能够阻止新建shard时扫描集群内全副shard的元数据,晋升shard调配速度cluster.routing.allocation.disk.include_relocations: false,默认为true零碎层面调优jdk版本选用以后版本ES举荐应用的ES,或者应用ES自带的JDKjdk内存配置首先,-Xms和-Xmx设置为雷同的值,防止在运行过程中再进行内存调配,同时,如果零碎内存小于64G,倡议设置略小于机器内存的一半,残余留给零碎应用,同时,jvm heap倡议不要超过32G(不同jdk版本具体的值会略有不同),否则jvm会因为内存指针压缩导致内存节约 ...

March 29, 2023 · 2 min · jiezi

关于java:5大主流方案对比MySQL千亿级数据线上平滑扩容实战

大家好,我是不才陈某~ 在我的项目初期,咱们部署了三个数据库A、B、C,此时数据库的规模能够满足咱们的业务需要。为了将数据做到平均分配,咱们在Service服务层应用uid%3进行取模分片,从而将数据平均分配到三个数据库中。 关注公众号:码猿技术专栏,回复关键词:1111 获取阿里外部Java性能优化手册!如图所示: 前期随着用户量的减少,用户产生的数据信息被源源不断的增加到数据库中,最终达到数据库的最佳存储容量。如果此时持续向数据库中新增数据,会导致数据库的CRUD等基本操作变慢,进而影响整个服务的响应速度。 这时,咱们须要减少新的节点,对数据库进行程度扩容,那么退出新的数据库D后,数据库的规模由原来的3个变为4个。 如图所示: 此时因为分片规定产生了变动(uid%3 变为uid%4),导致大部分的数据,无奈命中原有的数据,须要从新进行调配,要做大量的数据迁徙解决。 比方之前uid如果是uid=3取模3%3=0, 是调配在A库上,新退出D库后, uid=3取模3%4=3,调配在D库上; 新增一个节点, 大略会有90%的数据须要迁徙, 这样会面临大量的数据压力,并且对服务造成极大的不稳定性。 1. 五个计划1.1 停机计划 发布公告:为了进行数据的从新拆分,在进行服务之前,咱们须要提前告诉用户,比方:咱们的服务会在yyyy-MM-dd进行降级,给您带来的不便敬请体谅。进行服务:敞开Service离线数据迁徙(拆分,重新分配数据):将旧库中的数据依照Service层的算法,将数据拆分,重新分配数据数据校验:开发定制一个程序对旧库和新库中的数据进行校验,比对更改配置:批改Service层的配置算法,也就是将原来的uid%3变为uid%4复原服务:重启Service服务回滚预案:针对上述的每个步骤都要有数据回滚预案,一旦某个环节(如:数据迁徙,复原服务等)执行失败,立即进行回滚,从新再来进行服务之后, 可能保障迁徙工作的失常进行, 然而服务进行,挫伤用户体验, 并造成了工夫压力, 必须在指定的工夫内实现迁徙。 1.2 停写计划 反对读写拆散:数据库反对读写拆散,在扩容之前,每个数据库都提供了读写性能,数据重新分配的过程中,将每个数据库设置为只读状态,敞开写的性能降级布告:为了进行数据的从新拆分,在停写之前,咱们须要提前告诉用户,比方:咱们的服务会在yyyy-MM-dd进行降级,给您带来的不便敬请体谅。中断写操作,隔离写数据源(或拦挡返回对立提醒):在Service层对所有的写申请进行拦挡,对立返回提示信息,如:服务正在降级中,只对外提供读服务数据同步解决:将旧库中的数据依照Service层的算法,将数据重新分配,迁徙(复制数据)数据校验:开发定制一个程序对旧库中的数据进行备份,应用备份的数据和重新分配后的数据进行校验,比对更改配置:通过配置核心,批改Service层的配置算法,也就是将原来的uid%3变为uid%4,这个过程不须要重启服务复原写操作:设置数据库复原读写性能,去除Service层的拦挡提醒数据清理:应用delete语句对冗余数据进行删除回滚预案:针对上述的每个步骤都要有数据回滚预案,一旦某个环节(如:数据迁徙等)执行失败,立即进行回滚,从新再来毛病:在数据的复制过程须要耗费大量的工夫,停写工夫太长,数据须要先复制,再清理冗余数据 1.3 日志计划外围是通过日志进行数据库的同步迁徙, 次要操作步骤如下: 1、数据迁徙之前, 业务利用拜访旧的数据库节点。 2、日志记录 在降级之前, 记录“对旧数据库上的数据批改”的日志(这里批改包含增、删、改),这个日志不须要记录具体的数据信息,次要记录: (1)批改的库; (2)批改的表; (3)批改的惟一主键; (4)批改操作类型。 日志记录不必关注新增了哪些信息,批改的数据格式,只须要记录以上数据信息,这样日志格局是固定的, 这样能保障计划的通用性。 服务降级日志记录性能危险较小: 写和批改接口是多数, 改变点少; 降级只是减少了一些日志,采纳异步形式实现, 对业务性能没有太多影响。 3、数据迁徙: 研发定制数据迁徙工具, 作用是把旧库中的数据迁徙至新库中。 整个过程依然采纳旧库进行对外服务。 数据同步工具实现复杂度不高。 只对旧库进行读取操作, 如果同步呈现问题, 都能够对新库进行回滚操作。 能够限速或分批迁徙执行, 不会有工夫压力。 数据迁徙实现之后, 并不能切换至新库提供服务。 因为旧库仍然对线上提供服务, 库中的数据随时会发生变化, 但这些变动的数据并没有同步到新库中, 旧库和新库数据不统一, 所以不能间接进行切换, 须要将数据同步残缺。 4、日志增量迁徙 ...

March 29, 2023 · 9 min · jiezi

关于java:微信JSAPI支付-签名问题

jsapi微信底层就不过多形容了,次要记录一下,查了很多材料,发现微信返回参数不能间接返给前端应用,还须要进行一次签名,不然前台就会提醒签名谬误 // dic微信返回的 Map<String, String> reqData = new HashMap<>(); String timeStamp = String.valueOf(WXPayUtil.getCurrentTimestamp()); String prepay_id = "prepay_id=" + dic.get("prepay_id"); reqData.put("appId", dic.get("appid")); reqData.put("timeStamp", timeStamp); reqData.put("nonceStr", dic.get("nonce_str")); reqData.put("package", prepay_id); reqData.put("signType", WXPayConstants.MD5);应用MD5进行签名 String paySign = WXPayUtil.generateSignature(reqData, "微信商户号的key", WXPayConstants.SignType.MD5);返回前端参数 Map<String, String> data = new HashMap<>();data.put("appId", dic.get("appid"));data.put("timeStamp", timeStamp);data.put("nonceStr", dic.get("nonce_str"));data.put("package", prepay_id);data.put("paySign", paySign);data.put("signType", WXPayConstants.MD5);data.put("mch_id", dic.get("mch_id"));data.put("nvcOrderNumber", dic.get("out_trade_no"));前端调起领取 形容比较简单,只是记录,仅供参考

March 29, 2023 · 1 min · jiezi

关于java:Java并发编程-Lock-Condition-ReentrantLock一

Lock框架为java并发编程提供了除synchronized之外的另外一种抉择。synchronized是隐式实现,底层封装了对锁资源的获取和开释的所有实现细节,程序员不须要关怀也没有方法关怀这些细节,应用起来十分不便也十分平安。 而Lock由java语言实现,公开了锁资源获取和开释的所有细节,在资源锁定过程中提供了更多选项,在获取锁资源后,能够通过Condition对象对锁资源做细粒度的治理。 最要害的是Lock大量应用了CAS,充分利用“持有锁的线程不会长时间占用锁”这一假如,有可能的状况下就尽量先自旋、后锁定资源。所以多线程环境下Lock应该比synchronized有更好的性能。 java线程池框架Executor中大量应用了基于Lock接口的ReentrantLock,把握ReentrantLock是深刻了解各种Executor(ThreadPoolExecutor、ScheduledThreadPoolExecutor等)以及各种阻塞队列的必要前提。 Lock有独占锁、共享锁的区别,独占锁是指某一线程获取锁资源后即独占该锁资源、其余线程只能期待,共享锁是指多个线程能同时取得锁资源。 明天咱们的钻研对象是ReentrantLock,ReentrantLock是独占锁,次要钻研内容: ReentrantLock的基本概念根底数据机构:AQS,CLH队列偏心锁、非偏心锁Condition没有Condition参加的lock、unlock有Condition参加的lock、unlockReentrantLock的基本概念顾名思义,ReentrantLock是“可重入锁”,意思是同一线程能够屡次取得锁,n次取得须要n次开释能力最终开释掉ReentrantLock。 ReentrantLock的基本原理: 与synchronized不同,ReentrantLock不存在“锁对象”的概念,或者能够了解为锁对象就是ReentrantLock对象自身ReentrantLock设置一个状态值,通过对状态值的原子操作实现对锁资源的获取和开释,任何一个线程能获取锁资源的充沛必要条件是ReentrantLock处于闲暇状态,同理,任何一个线程取得锁资源后ReentrantLock即处于占用状态ReentrantLock的两个最根本的操作:lock和unlock,lock获取锁资源,unlock开释锁资源ReentrantLock保护一个CLH队列,CLH队列是一个先进先出的双向队列ReentrantLock处于闲暇状态则lock调用立刻返回,调用线程取得锁资源。否则,申请线程进入CLH队列排队,期待被其余线程唤醒取得锁资源的线程在业务执行实现后调用unlock开释锁资源,之后以FIFO的准则唤醒最先进入队列排队的线程被唤醒的线程继续执行lock操作,节点从CLH队列出队,返回---意味着申请锁资源的线程在期待后获取锁资源胜利,持续第6步的逻辑以上是没有Condition对象参加的ReentrantLock的获取、开释锁资源的逻辑,绝对比较简单。 有Condition参加的时候,状况会略微简单一点: ReentrantLock对象能够通过new Condition()操作持有Condition对象,一个ReentrantLock能够持有多个Condition对象Condition保护一个Condition队列Condition的罕用的操作包含await、signal等,执行操作的时候假如以后线程曾经获取到了ReentrantLock锁资源await操作会开释掉以后线程曾经获取到的ReentrantLock锁资源、挂起以后线程,并且将以后线程退出Condition的队列排队期待被其余线程唤醒。比方DelayedWorkQueue的take办法中,如果以后DelayedWorkQueue队列空的话,则take线程退出到命名为available的Condition中排队等待当相干操作可能导致Condition的条件满足的时候,调用Condition的signal办法唤醒在Condition队列中期待的线程。比方上例中DelayedWorkQueue的add办法实现之后,调用available的signal办法,唤醒在available队列中排队等待的线程。线程被唤醒之后从Condition队列出队,进ReentrantLock的CLH队列排队期待从新获取锁资源Condition举例:take办法中队列空的话,挂起期待 Condition举例:offer办法中写入队列后,唤醒期待的线程 对ReentrantLock应该有一个根本的意识了,如果只是想要对ReentrantLock做一个根本理解、可能看懂ReentrantLock的利用、而不是要从源码角度做深入研究的话,集体认为把握下面这些基本原理应该就够了,保障能看懂阻塞队列、线程池中的无关ReentrantLock的源码逻辑了。 然而如果想要彻底搞清楚ReentrantLock到底是怎么实现以上逻辑的,就须要从源码角度持续做深入研究了。 ReentrantLock数据结构:AQS及CLH队列多个线程同时竞争ReentrantLock锁资源的时候,只能有一个竞争获胜的线程取得锁资源、其余线程就只能排队期待。这个用来排队的队列就是CLH队列,AQS(AbstractQueuedSynchronizer)是实现CLH队列的虚构类。 ReentrantLock有一个十分重要的属性Sync,Sync是AQS的虚构扩大类,Sync有两个实现类:NonfairSync和FairSync,类构造如下: NonfairSync和FairSync都是AQS的最终实现,AQS虚构类是一个规范模板,定义了Lock锁的根本数据结构(阻塞队列)、并实现了Lock的绝大部分性能。 进入队列排队的线程被封装为Node,Node是AQS定义的外部类,是咱们学习AQS首先要把握的内容。 Node的重要属性:waitStatus:期待状态,Node就是用来排队的,waitStatus就代表以后节点的期待状态,有以下几种期待状态: CANCELLED = 1:示意以后期待线程曾经被calcel掉了SIGNAL = -1:示意该节点是在CLH队列中排队期待出队CONDITION = -2:示意以后节点是在Condition队列中期待出队PROPAGATE = -3:共享锁会用到,暂不剖析prev:上一节点next:双向队列嘛,当然也要有下一节点Thread thread:节点的配角,排队线程nextWaiter:Condition队列专用,用来指向Condition队列的下一节点 AQS的同步队列(CLH)以及Condition队列的节点都是用这个Node,所以Node类做了一部分针对两者的兼容设计,比方nextWaiter是针对Condtion队列的下一节点,next是针对CLH的下一节点。 AQS重要属性state:锁状态,通过对state的原子操作实现对锁资源的管制:某一线程通过原子操作胜利将state从闲暇批改为占用则意味着以后线程胜利取得了锁资源。无奈取得锁资源的线程则封装为Node节点进入队列排队期待。 head:首节点,头节点tail:尾结点 通过head节点、tail节点,以及每个节点的prev、next,AQS实现了一个双向队列。 偏心锁和非偏心锁所谓的偏心锁和非偏心锁就是由Sync属性决定的:当Sync创立为NonfairSync的时候,就是非偏心的ReentrantLock,否则就是偏心的ReentrantLock。 应用无参结构器创立的是非偏心ReentrantLock,有参结构器ReentrantLock(boolean fair)能够通过参数指定创立偏心还是非偏心锁。 偏心锁在线程申请锁资源的时候会查看CLH队列,队列不空的话首先进入队列排队,先提出申请的线程会优先取得锁资源,因而是“偏心”的锁。 非偏心锁在线程申请锁资源的时候不会查看CLH队列,间接尝试取得锁资源,获取失败后才进入队列排队。所以申请线程会失去比队列中的线程更高的优先级,对于队列中排队的线程来说是不偏心的,所以叫非偏心锁。 ConditionCondition提供await和signal(以及他们的变种)办法为ReentrantLock锁资源提供更多抉择:以后线程获取到ReentrantLock锁资源后,能够通过Condition对象的await办法挂起以后线程直到其余线程通过该对象的signal办法唤醒。 一个ReentrantLock能够创立多个Condition对象,每一个Condition对象都是独立的、互不影响。ReentrantLock好比是一条街上的黑社会老大,黑社会老大首先要把这条街拿下,也就是取得ReentrantLock锁资源。之后的每一个Condition好比是这条街道上的饭店A、小卖店B、公共卫生间C,别离对应ConditionObjectA、ConditionObjectB、ConditionObjectC,失去黑社会老大容许后你就能够随便进出饭店吃饭了,然而如果饭店客满了,就必须通过调用ConditionObjectA的await办法进入到ConditionObjectA的队列中排队期待(以后线程封装为AQS中的Node进入队列(假如叫NodeA),以后线程A挂起),此时黑社会老大须要交出对整条街的锁权限(貌似不太正当...),尔后饭店A有人吃完了要离店,就会通过ConditionObjectA的signal办法告诉正在队列中排队等待的NodeA,于是NodeA从ConditionObjectA队列中进去,到ReentrantLock的CLH队列中排队、期待从新获取ReentrantLock锁资源之后再唤醒线程A。这个过程中如果有其他人(其余线程)要进入小卖店B,须要进行操作的就是小卖店对应的ConditionObjectB,和饭店对应的ConditionObjectA没有任何关系。 小结发现开篇定下的内容太多了,篇幅所限,前面的“没有Condition参加的lock、unlock”以及“有Condition参加的lock、unlock”,根本就是上述逻辑的源码剖析,放在下一篇。 Thanks a lot! 上一篇 周期性工作线程池 - ScheduledThreadPoolExecutor & DelayedWorkQueue

March 28, 2023 · 1 min · jiezi

关于java:面试1v1实景模拟面试中常见的Java关键字详解

老面:Java中有哪些关键字笑小枫: 用于数据类型用于数据类型的关键字有 boolean、byte、char、 double、 float、int、long、new、short、void、instanceof。用于语句用于语句的关键字有break、case、 catch、 continue、 default 、do、 else、 for、 if、return、switch、try、 while、 finally、 throw、this、 super。用于润饰用于润饰的关键字有 abstract、final、native、private、 protected、public、static、synchronized、transient、 volatile。用于办法、类、接口、包和异样用于办法、类、接口、包和异样的关键字有 class、 extends、 implements、interface、 package、import、throws。其余还有些关键字,如 future、 generic、 operator、 outer、rest、var等都是Java保留的没有意义的关键字。另外,Java还有3个保留字:goto、const、null。它们不是关键字,而是文字。蕴含Java定义的值。和关键字一样,它们也不能够作为标识符应用。老面:简略介绍一下 final 关键字笑小枫:final关键字能够用来润饰援用、办法和类。 润饰援用如果援用为根本数据类型,则该援用为常量,该值无奈批改;如果援用为援用数据类型,比方对象、数组,则该对象、数组自身能够批改,但指向该对象或数组的地址的援用不能批改。如果援用时类的成员变量,则必须当场赋值,否则编译会报错。润饰办法当应用final润饰办法时,这个办法无奈被子类重写。然而,该办法依然能够被继承。润饰类当用final批改类时,该类成为最终类,无奈被继承。老面:简略介绍一下 this、super 关键字笑小枫:this:代表以后对象的援用,谁来调用我我就代表谁。super:代表以后对象对父类的援用。 调用成员变量不同;this:成员变量 调用本类的成员变量,也能够调用父类的成员变量。 super:成员变量 调用父类的成员变量。调用构造方法不同。this:调用本类的构造方法。 super:调用父类的构造方法。调用成员办法。this:成员办法 调用本类的成员办法,也能够调用父类的办法。 super:成员办法 调用父类的成员办法。老面:简略介绍一下 static 关键字笑小枫: static是一个修饰符,用于润饰成员。(成员变量,成员函数)static润饰的成员变量 称之为动态变量或类变量。static润饰的成员被所有的对象共享。static优先于对象存在,因为static的成员随着类的加载就曾经存在。static润饰的成员多了一种调用形式,能够间接被类名所调用,(类名.动态成员)。static润饰的数据是共享数据,对象中的存储的是特有的数据。老面:简略介绍一下 volatile 关键字笑小枫:volatile是java虚拟机提供的轻量级同步机制,用于示意能够被多个线程异步批改的成员变量,其特点有: 1.保障可见性 2.禁止指令重排 3.不保障原子性 1、volatile可见性实现原理: 变量被volatile关键字润饰后,底层汇编指令中会呈现一个lock前缀指令。会导致以下两种事件的产生: 批改volatile变量时,会强制将批改后的值刷新到主内存中。批改volatile变量后,会导致其余线程工作内存中对应的变量值生效。因而,再读取该变量值的时候就须要从新从读取主内存中的值。2、volatile有序性实现原理: 指令重排序:编译器在不扭转单线程程序语义的前提下,重新安排语句的执行程序,指令重排序在单线程下不会有问题,然而在多线程下,可能会呈现问题。 volatile有序性的保障就是通过禁止指令重排序来实现的。指令重排序包含编译器和处理器重排序,JMM会别离限度这两种指令重排序。禁止指令重排序又是通过加内存屏障实现的。 JMM:JMM(java 内存模型 Java Memory Model 简称JMM) 自身是一个形象的概念,并不在内存中实在存在的,它形容的是一组标准或者规定,通过这组标准定义了程序中各个变量(实例字段,动态字段和形成数组对象的元素)的拜访形式.JMM的同步规定: 1.线程解锁之前,必须把共享变量刷新回主存 2.线程加锁锁之前,必须读取主存的最新值到本人的工作空间 3.加锁解锁必须是 同一把锁内存屏障(memory barriers):一组处理器指令,用于实现对内存操作的程序限度。 3、 volatile为什么不保障原子性? ...

March 28, 2023 · 1 min · jiezi

关于java:这年头谁的好友列表还没有躺一个ChatGPT啊

你要是说这个,我可不困了 大家好,我最近开始应用一款十分乏味的AI机器人,它叫做ChatGPT。ChatGPT是一款独特的聊天机器人,它能够进行智能对话,答复你的问题,还能够学习你的语言习惯,使得对话更加晦涩和天然。 ChatGPT的利用十分宽泛,它可能利用在语言学习、客户服务、人机交互等多个畛域。无论你是学生、工程师、普通用户,都能够从中取得帮忙。 于是,我将chatGPT的能力赋予了我的聊天机器人~大家能够观看一下成果<iframe src="//player.bilibili.com/player.html?aid=311143188&bvid=BV1TP411f7X8&cid=1059111407&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" width = "100%" height=500> </iframe> 如果你也对ChatGPT感兴趣,欢送退出我的群聊,咱们能够一起摸索这个聊天机器人的神秘。 在这个群聊中,咱们能够分享咱们的教训和想法,互相帮助和反对。 ChatGPT是一个优良的AI机器人,值得一试,我置信你肯定会喜爱上它。如果你想退出我的ChatGPT群,请关注微信公众号:程序员小明,回复ChatGPT拉你进群。<img src="https://img.mynamecoder.com/coderxm_qrcode.jpeg" width="200" height="200" align="center" /> <font color=red>以上文案出自ChatGPT</font>本文可转载,但需申明原文出处。 程序员小明,一个很少加班的程序员。欢送关注微信公众号“程序员小明”,获取更多优质文章。

March 28, 2023 · 1 min · jiezi

关于java:基于OpenAI的代码编辑器有点酷有点强

最近随着OpenAI的一系列大动作,把软件畛域搅的翻天覆地。各行各业各畛域,都呈现了大量新产品。 开发工具畛域首当其冲,各种新工具层出不穷,明天TJ就给大家举荐一个全新的开发工具:Cursor 从官网介绍能够看到,Cursor基于OpenAI实现,继承了最新的GPT-4模型,反对Mac、Windows、Linux三大平台。 上面大家看看这个开发工具有多厉害,理性趣味的读者也能够通过下方链接去官网下载了一起体验: 官方网站:https://www.cursor.so/生成代码通过快捷键cmd + k唤出AI指令输入框 比方,我这里输出“读取文件”。马上就产生了上面的实现内容: 解释代码选中你看不懂的代码,按快捷键cmd + L说出你的疑难,AI在右侧就会给出解释 这性能兴许十分实用吧,毕竟咱们每天都在保护屎山,有了这根搅屎棍的帮忙,兴许屎山啃起来能够容易一些了吧! 起源:基于OpenAI的代码编辑器:Cursor 欢送关注我的公众号:程序猿DD。第一工夫理解前沿行业音讯、分享深度技术干货、获取优质学习资源

March 28, 2023 · 1 min · jiezi

关于java:头铁面试官一个小小的-Systemoutprintln-硬是考了我半个小时被问懵了

起源:cnblogs.com/blessing2022/p/16622118.html 去年秋招面试我被问及: 你如何了解 System.out.println()?学了这么久的面向对象编程,那如何用一行代码体现呢? 如果你能本人读懂System.out.println(),就真正理解了Java面向对象编程的含意。 面向对象编程即创立了对象,所有的事件让对象帮亲力亲为(即对象调用办法)System.out.println("hello world");hello worldProcess finished with exit code 0首先剖析System源码: System就是Java自定义的一个类 这也是 IO 方面的面试题,如果你近期筹备面试跳槽,倡议在Java面试库小程序在线刷题,简直笼罩了所有支流技术面试题。 out源码剖析 ①out是System外面的一个静态数据成员,而且这个成员是java.io.PrintStream类的援用 ②out曾经存在了且用Static润饰了,所以能够间接应用类名+属性名的形式调用,也就是System.out。 println剖析 ①println()就是java.io.PrintStream类里的一个办法,它的作用是向控制台输入信息。 ②外面有很多重载的办法,这样就保障了任意的货色都能够输入 小结下来就是:类调用对象,对象调用办法拓展知识点 :1.System.out.print();与System.out.println();的区别 2.字符数组输入面试案例public class Demo { public static void main(String[] args) { char[] ch=new char[]{'x','y'}; System.out.println(ch); char[] ch1=new char[]{'x','y'}; System.out.println("ch1="+ch1); }}xych1=[C@74a14482这是println()办法的重载,java打印输出System.out.println会主动调用输出参数的toString办法,输入内容时toString办法的返回值。 println的参数分根本类型,一个是String 另一个是Object类型。 System.out.println(ch),println()主动调用println(char[]) 也就是Object类型 所以输入xy 然而System.out.println(“ch=”+ch) "+"是字符串连接符,主动调用println(String),也就是String类型 输入的是xxx@xxxx的模式。 近期热文举荐: 1.1,000+ 道 Java面试题及答案整顿(2022最新版) 2.劲爆!Java 协程要来了。。。 3.Spring Boot 2.x 教程,太全了! 4.别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!! ...

March 28, 2023 · 1 min · jiezi

关于java:JSON-与-Java-对象之间的转化

前言在当初的日常开发中,不论前端还是后端,JSON 格局的数据是用得比拟多的,甚至能够说无处不在。 接触最多的就是 POST 申请中传递的数据个别以 JSON 的格局放在申请体中,而且服务端各种 API 返回的数据,在响应体中也根本都是以 JSON 格局的数据进行返回的,这也是 RESTful 格调的体现之一。 当然,不止是申请与响应的过程中应用到 JSON,在某些业务场景下也是须要用到 JSON 的,特地是 JSON 与 Java 对象之间的转化。 所以,对于 Java 开发的咱们来说,JSON 格局的数据与 Java 对象之间的转化是必会的。 转化的工具支流的转化工具有如下几种,个别我的项目中倡议只选其中一种,目前好评最多的感觉就是 Jackson 了。 JacksonFastJsonGsonHutool筹备的 JSON 字符串和 List为了不便演示,这里给出一个 JSON 字符串: String jsonStr = "{\"name\" : \"GTA5\", \"price\" : 54.5}";这里给出一个 List<Game>: Game game1 = Game.builder().name("NBA2K23").price(new BigDecimal("198.0")).build();Game game2 = Game.builder().name("Sim City4").price(new BigDecimal("22.5")).build();List<Game> gameList = new ArrayList<>();gameList.add(game1);gameList.add(game2);Jackson咱们须要借助 Jackson 提供的 ObjectMapper 对象来实现转化: ObjectMapper objectMapper = new ObjectMapper();将 JSON 字符串 转成 Java 对象:readValue应用 readValue 办法,第一个参数是 JSON 字符串,第二个参数是转化的指标类的类型。 ...

March 27, 2023 · 3 min · jiezi

关于java:EasyRelation-发布简单强大的数据关联框架

当开发人员须要进行关联查问时,往往须要编写大量的冗余代码来解决数据之间的关系。这不仅浪费时间和精力,还会影响我的项目的可维护性和可扩展性。 EasyRelation 是一个简略、高效的主动关联数据框架,能够通过一行代码,主动关联查问并填充须要的数据,对于性能影响极小,且省略了大量的冗余代码。 该框架适应于以后对象中的字段须要关联查问,并赋值到以后对象的字段中,数据起源能够是枚举、数据库、RPC 接口等等任意起源。 特点不限度关联查问形式,须要关联的数据能够是任意起源两级缓存反对,可自由选择应用的缓存执行效率高,对性能影响极小反对多条件关联和常量条件关联疾速开始上面演示如何应用 EasyRelation 进行主动关联数据 假如有订单类(Order)和用户类(User),订单中保留了用户名,须要关联查问用户昵称。 Order@Datapublic class Order { private String orderId; private String username; private String nickName;}User@Datapublic class User { private String username; private String nickName;}增加依赖<properties> <easy-relation.version>最新版本</easy-relation.version></properties><dependencies> <dependency> <groupId>cn.easii</groupId> <artifactId>easy-relation-spring-boot-starter</artifactId> <version>${easy-relation.version}</version> </dependency></dependencies>定义用户数据数据提供者这里须要定义一个类,实现 DataProvideService 接口,在其中定义获取用户信息的接口,并增加 @DataProvider 注解。 @Componentpublic class UserInfoDataProvider implements DataProvideService { @DataProvider(RelationIdentifiers.getUserByUsername) public User getUserByUsername(UserQueryReq req) { if ("admin".equals(req.getUsername())) { final User user = new User(); user.setUsername("admin"); user.setNickName("管理员"); return user; } return null; }}这里的 UserQueryReq 为用户信息查问入参,定义如下: ...

March 27, 2023 · 1 min · jiezi

关于java:三天吃透MySQL面试八股文

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/Java-learning 什么是MySQLMySQL是一个关系型数据库,它采纳表的模式来存储数据。你能够了解成是Excel表格,既然是表的模式存储数据,就有表构造(行和列)。行代表每一行数据,列代表该行中的每个值。列上的值是有数据类型的,比方:整数、字符串、日期等等。 数据库的三大范式第一范式1NF 确保数据库表字段的原子性。 比方字段 userInfo: 广东省 10086' ,按照第一范式必须拆分成 userInfo: 广东省 userTel: 10086两个字段。 第二范式2NF 首先要满足第一范式,另外蕴含两局部内容,一是表必须有一个主键;二是非主键列必须齐全依赖于主键,而不能只依赖于主键的一部分。 举个例子。假设选课关系表为student_course(student_no, student_name, age, course_name, grade, credit),主键为(student_no, course_name)。其中学分齐全依赖于课程名称,姓名年龄齐全依赖学号,不合乎第二范式,会导致数据冗余(学生选n门课,姓名年龄有n条记录)、插入异样(插入一门新课,因为没有学号,无奈保留新课记录)等问题。 应该拆分成三个表:学生:student(stuent_no, student_name, 年龄);课程:course(course_name, credit);选课关系:student_course_relation(student_no, course_name, grade)。 第三范式3NF 首先要满足第二范式,另外非主键列必须间接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的状况。 假设学生关系表为Student(student_no, student_name, age, academy_id, academy_telephone),主键为"学号",其中学院id依赖于学号,而学院地点和学院电话依赖于学院id,存在传递依赖,不合乎第三范式。 能够把学生关系表分为如下两个表:学生:(student_no, student_name, age, academy_id);学院:(academy_id, academy_telephone)。 2NF和3NF的区别? 2NF根据是非主键列是否齐全依赖于主键,还是依赖于主键的一部分。3NF根据是非主键列是间接依赖于主键,还是间接依赖于非主键。事务的四大个性?事务个性ACID:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。 原子性是指事务蕴含的所有操作要么全副胜利,要么全副失败回滚。一致性是指一个事务执行之前和执行之后都必须处于一致性状态。比方a与b账户共有1000块,两人之间转账之后无论胜利还是失败,它们的账户总和还是1000。隔离性。跟隔离级别相干,如read committed,一个事务只能读到曾经提交的批改。持久性是指一个事务一旦被提交了,那么对数据库中的数据的扭转就是永久性的,即使是在数据库系统遇到故障的状况下也不会失落提交事务的操作。最全面的Java面试网站事务隔离级别有哪些?先理解下几个概念:脏读、不可反复读、幻读。 脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。不可反复读是指在对于数据库中的某行记录,一个事务范畴内屡次查问却返回了不同的数据值,这是因为在查问距离,另一个事务批改了数据并提交了。幻读是当某个事务在读取某个范畴内的记录时,另外一个事务又在该范畴内插入了新的记录。对幻读的正确理解是一个事务内的读取操作的论断不能撑持之后业务的执行。假如事务要新增一条记录,主键为id,在新增之前执行了select,没有发现id为xxx的记录,但插入时呈现主键抵触,这就属于幻读,读取不到记录却发现主键抵触是因为记录实际上曾经被其余的事务插入了,但以后事务不可见。不可反复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可反复读则是读取了前一事务提交的数据。 事务隔离就是为了解决下面提到的脏读、不可反复读、幻读这几个问题。 MySQL数据库为咱们提供的四种隔离级别: Serializable (串行化):通过强制事务排序,使之不可能互相抵触,从而解决幻读问题。Repeatable read (可反复读):MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行,解决了不可反复读的问题。Read committed (读已提交):一个事务只能看见曾经提交事务所做的扭转。可防止脏读的产生。Read uncommitted (读未提交):所有事务都能够看到其余未提交事务的执行后果。查看隔离级别: select @@transaction_isolation;设置隔离级别: set session transaction isolation level read uncommitted;生产环境数据库个别用的什么隔离级别呢?生产环境大多应用RC。为什么不是RR呢? ...

March 27, 2023 · 6 min · jiezi

关于java:面试1v1实景模拟Spring事务全方位解读面试官心理助你一面入坑

老面:小伙子,理解Spring的事务吗?解读:这个必须理解,不理解间接挂~,但面试官必定不是想听你理解两个字,他是想让你简略的介绍下。 笑小枫:理解,事务在逻辑上是一组操作,要么执行,要不都不执行。次要是针对数据库而言的,比如说 MySQL。为了保障事务是正确牢靠的,在数据库进行写入或者更新操作时,就必须得体现出 ACID 的 4 个重要个性。 老面:你刚刚提到了ACID,那你简略的介绍一下这4个个性解读:在介绍事务的时候,本能够把个性介绍了,然而偏偏不,成心一提,但不开展形容。为的就是让老面进入到咱们的节奏尽管是你面试我,但我要牵着你的鼻子走,面试就是一场心理战,这才刚刚开始~ 笑小枫:ACID别离是原子性(Atomicity)、一致性(Consistency)、事务隔离(Isolation)、持久性(Durability)。 其中:原子性(Atomicity)是一个事务中的所有操作,要么全副实现,要么全副不实现,不会完结在两头某个环节。事务在执行过程中产生谬误,会被回滚(Rollback)到事务开始前的状态,就像这个事务素来没有执行过一样。 一致性(Consistency)是在事务开始之前和事务完结当前,数据库的完整性没有被毁坏。 事务隔离(Isolation)是数据库容许多个并发事务同时对其数据进行读写和批改,隔离性能够避免多个事务并发执行时因为穿插执行而导致数据的不统一。 持久性(Durability)是事务处理完结后,对数据的批改就是永恒的,即使系统故障也不会失落。 正是因为这4个个性,咱们在我的项目中会频繁的应用事务。 老面:你刚刚说,在我的项目中频繁应用事务,都是什么场景下应用的呢?解读:又跟着节奏来了,这个比较简单 笑小枫:事务应用场景分为两种读写事务和只读事务。 咱们罕用的场景中,多表操作的时候会应用读写事务,例如A转账给B的时候,须要A扣款胜利, B到账胜利,就要用到事务的原子性、一致性和持久性;在多表查问的时候,咱们会用到只读事务,例如A有1000元,B有2000元,这个时候总金额应该为3000元。 select amount from user where id = 'A';select amount from user where id = 'B';如果查问完A后取到了1000元,而后A转账给B 1000元,如果没有事务,查问到B为3000元,这个时候总额就是4000元了,所以能够应用只读事务,保证数据的隔离性和一致性。 老面:你能说说具体是怎么应用的吗?笑小枫:事务应用个别有管理机制,一种是编程式事务,就是在代码中手动的治理事务的提交、回滚等操作,代码侵入性比拟强,咱们很少应用;另外一种是申明式事务,应用@Transactional注解,它是基于AOP面向切面的,将具体业务与事务处理局部解耦,代码侵入性很低,咱们我的项目中应用这种形式比拟多。 老面:你刚刚提到了Transactional,你晓得它有几种作用域吗?笑小枫:能够作用在类、办法、接口上; 当把注解放在类上时,示意所有该类的public办法都配置雷同的事务属性信息。 当类配置了@Transactional,办法也配置了@Transactional,办法的事务会笼罩类的事务配置信息。 不举荐作用在接口上,因为这只有在应用基于接口的代理时它才会失效,一旦配置了Spring AOP应用CGLib动静代理,将会导致@Transactional注解生效。 老面:除了作用在类上时,Spring AOP应用CGLib动静代理,@Transactional会生效外,你还晓得其它的场景会导致事务生效吗?解读:这还不简略,这不就是我给你挖的坑嘛列举几种状况吧,抽几条说就行,老面必定会觉着你这小子根底不错 笑小枫: @Transactional 利用在非 public 润饰的办法上 如果Transactional注解利用在非public 润饰的办法上,Transactional将会生效。 起因是:TransactionInterceptor (事务拦截器)应用AOP,在指标办法执行前后进行拦挡,会查看指标办法的修饰符是否为 public,不是 public则不会获取@Transactional 的属性配置信息。(spring要求被代理办法必须是public的。) @Transactional 注解属性 propagation 设置谬误这种是因为propagation的参数设置谬误,依据需要抉择适合的@Transactional的propagation属性的值@Transactional 注解属性 rollbackFor 设置谬误 rollbackFor默认是error和RuntimeException会触发回滚,其余异样或自定义异样不会回滚,须要回滚则须要指定或者间接指定@Transactional(rollbackFor=Exception.class) 同一个类中办法调用,导致@Transactional生效 这个和redis缓存生效场景之一一样,如果在一个类中,B办法加了事务,A办法没加事务调用B办法,另外一个类调用A办法,则B办法的事务生效。这种状况能够加一层Mamager层对Service层通用能力的下沉。 异样被捕捉,导致@Transactional生效 当咱们是用catch把异样捕捉了,那么该办法就不会抛出异样了,那么呈现该异样就不会回滚了 数据库引擎不反对事务 这种状况呈现的概率并不高,事务是否失效数据库引擎是否反对事务是要害。罕用的MySQL数据库默认应用反对事务的innodb引擎。一旦数据库引擎切换成不反对事务的myisam,那事务就从根本上生效了。 ...

March 27, 2023 · 1 min · jiezi

关于java:二叉树的遍历Java版

递归最简略,迭代要用栈(其实也是模仿递归)。前序遍历递归/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */class Solution { List<Integer> res = new ArrayList<Integer>(); public List<Integer> preorderTraversal(TreeNode root) { if(root == null) return res; res.add(root.val); preorderTraversal(root.left); preorderTraversal(root.right); return res; }}迭代class Solution { List<Integer> res = new ArrayList<Integer>(); Stack<TreeNode> stack = new Stack<TreeNode>(); public List<Integer> preorderTraversal(TreeNode root) { if(root == null) return res; //前序根节点间接拜访 stack.push(root); while(!stack.isEmpty()) { TreeNode cur = stack.pop(); res.add(cur.val); if(cur.right != null) { stack.push(cur.right); } if(cur.left != null) { stack.push(cur.left); } } return res; }}中序遍历递归class Solution { List<Integer> res = new ArrayList<Integer>(); public List<Integer> inorderTraversal(TreeNode root) { if(root == null) return res; inorderTraversal(root.left); res.add(root.val); inorderTraversal(root.right); return res; }}迭代class Solution { List<Integer> res = new ArrayList<Integer>(); Stack<TreeNode> stack = new Stack<TreeNode>(); public List<Integer> inorderTraversal(TreeNode root) { if(root == null) return res; //中序 左-根-右 while(root != null || !stack.isEmpty()) { //根节点不空就间接压栈 if(root != null) { stack.push(root); root = root.left; }else{ //根节点为空出栈间接拜访左节点 root = stack.pop(); res.add(root.val); root = root.right; } } return res; }}后序遍历递归class Solution { List<Integer> res = new ArrayList<Integer>(); public List<Integer> postorderTraversal(TreeNode root) { if(root == null) return res; postorderTraversal(root.left); postorderTraversal(root.right); res.add(root.val); return res; }}迭代class Solution { LinkedList<Integer> res = new LinkedList<Integer>(); Stack<TreeNode> stack = new Stack<TreeNode>(); public List<Integer> postorderTraversal(TreeNode root) { if(root == null) return res; //根节点最初拜访先入栈 stack.push(root); while(!stack.isEmpty()) { TreeNode cur = stack.pop(); res.addFirst(cur.val); if(cur.left != null) { stack.push(cur.left); } if(cur.right != null) { stack.push(cur.right); } } return res; }}

March 27, 2023 · 2 min · jiezi

关于java:必须收藏别再乱找TiDB-集群部署教程了这篇保姆级教程来帮你-博学谷狂野架构师

TiDB 根底应用 TiDB dashboard应用TiDB Dashboard 是 TiDB 自 4.0 版本起提供的图形化界面,可用于监控及诊断 TiDB 集群。TiDB Dashboard 内置于 TiDB 的 PD 组件中,无需独立部署。 集群详情查看集群整体 QPS 数值、执行耗时、耗费资源最多的几类 SQL 语句等详情信息。 该页面显示了整个集群的详情,蕴含以下信息: 整个集群的 QPS整个集群的查问提早最近一段时间内累计耗时最多的若干 SQL 语句最近一段时间内运行工夫超过肯定阈值的慢查问各个实例的节点数和状态监控及告警信息QPS该区域显示最近一小时整个集群的每秒胜利和失败查问数量 留神:该性能仅在部署了 Prometheus 监控组件的集群上可用,未部署监控组件的状况下会显示为失败。提早该区域显示最近一小时整个集群中 99.9%、99% 和 90% 查问的提早: 留神:该性能仅在部署了 Prometheus 监控组件的集群上可用,未部署监控组件的状况下会显示为失败。Top SQL 语句该区域显示最近一段时间内整个群集中累计耗时最长的 10 类 SQL 语句。查问参数不一样但构造一样的 SQL 会归为同一类 SQL 语句,在同一行中显示 留神:该性能仅在开启了 SQL 语句剖析性能的集群上可用。最近的慢查问该区域默认显示最近 30 分钟内整个集群中最新的 10 条慢查问 默认状况下运行工夫超过 300ms 的SQL 查问即会被计为慢查问并显示在该表格中。集群信息该页面上容许用户查看整个集群中 TiDB、TiKV、PD、TiFlash 组件的运行状态及其所在主机的运行状态。实例列表实例列表列出了该集群中 TiDB、TiKV、PD 和 TiFlash 组件所有实例的详情信息。 表格列解释表格蕴含以下列:地址:实例地址状态:实例的运行状态启动工夫:实例的启动工夫版本:实例版本号部署门路:实例二进制文件所在目录门路Git 哈希值:实例二进制对应的 Git 哈希值实例状态解释实例的运行状态有:在线 (Up):实例失常运行。离线 (Down) 或无法访问 (Unreachable):实例未启动或对应主机存在网络问题。已缩容下线 (Tombstone):实例上的数据已被残缺迁出并缩容结束。仅 TiKV 或 TiFlash 实例存在该状态。下线中 (Offline):实例上的数据正在被迁出并缩容。仅 TiKV 或 TiFlash 实例存在该状态。未知 (Unknown):未知的实例运行状态。主机列表主机列表列出了该集群中 TiDB、TiKV、PD 和 TiFlash 组件所有实例对应主机的运行状况。 ...

March 27, 2023 · 4 min · jiezi