• [技术干货] Java 类型信息详解和反射机制介绍
    RTTIRTTI(RunTime Type Information)运行时类型信息,能够在程序运行时发现和使用类型信息,把我们从只能在编译期知晓类型信息并操作的局限中解脱出来传统的多态机制正是 RTTI 的基本使用:假设有一个基类 Shape 和它的三个子类 Circle、Square、Triangle,现在要把 Circle、Square、Triangle 对象放入 List<Shape> 中,在运行时,先把放入其中的所有对象都当作 Object 对象来处理,再自动将类型转换为 Shape。所有类型转换的正确性检查都是在运行时进行的,这也正是 RTTI 的含义所在:在运行时,识别一个对象的类型但这样的类型转换并不彻底,Object 只是被转型为 Shape,而不是更具体的 Circle、Square、Triangle,如果我们希望得到更具体的类型呢?比如说我们现在需要旋转所有图形,但是想跳过圆形(圆形旋转没有意义),这时可以使用 RTTI 查询某个 Shape 引用所指向对象的确切类型,然后选择进行合适的处理Class 对象众所周知,每当我们编写并编译了一个新类,就会产生一个 Class 对象,它包含了与类有关的信息。我们可以使用 Class 对象来实现 RTTI,一旦某个类的 Class 对象被载入内存,它就可以用来创建这个类的所有对象Class 对象都属于 Class 类型,既然它也是对象,那我们就可以获取和操控它的引用。forName() 是 Class 类的一个静态方法,我们可以使用 forName() 根据目标类的全限定名(包含包名)得到该类的 Class 对象。使用 forName() 会有一个副作用,那就是如果这个类没有被加载就会加载它,而在加载的过程中,Gum 类的 static 初始块会被执行。当 Class.forName() 找不到要加载的类,就会抛出异常ClassNotFoundExceptionClass gumClass = Class.forName("Gum");使用 Class.forName() 你不需要先持有这个类型的对象,但如果你已经拥有了目标类的对象,那就可以通过调用 getClass() 方法来获取 Class 引用,这个方法来自根类 Object,它将返回表示该对象实际类型的 Class 对象的引用Gum gum = new Gum();Class gumClass = gum.getClass();另外,你还可以调用 getSuperclass() 方法来得到父类的 class 对象,再用父类的 Class 对象调用该方法,重复多次,你就可以得到一个完整的类继承结构Class 对象的 newInstance() 方法可以让你在不知道一个的确切类型的时候创建这个类的对象,使用 newInstance() 来创建的类,必须带有无参数的构造器Object obj = gumClass.newInstance();当然,由于得到的是 Object 的引用,目前你只能给它发送 Object 对象能接受的调用。如果你想请求具体对象才有的调用,你就得先获取该对象的更多类型信息,并执行转型Java 还提供了另一种生成类对象的引用:类字面常量,这样做不仅更简单,而且更安全,因为它在编译时就会收到检查(不用放在 try 语句块中),而且根除了对 forName() 方法的调用,效率更高Class gumClass = Gum.class;类字面常量不仅可以用于普通类,也可以用于接口、数组以及基本数据类型。对于基本数据类型的包装类,还有一个标准字段 Type,Type 字段是一个引用,指向对应基本数据类型的 Class 对象,例如 int.class 就等价于 Integer.TYPE。还有一点值得注意的是:使用 .class 语法来获得对类对象的引用不会触发初始化到这里我们都知道了,Class 引用总是指向某个 Class 对象,而 Class 对象可以用于产生类的实例。不过自从 Java 引入泛型以后,我们就可以使用泛型对 Class 引用所指向的 Class 对象的类型进行限定,让它的类型变得更具体些Class intClass = int.class; Class<Integer> genericIntClass = int.class; intClass = genericIntClass; // 同一个东西 // genericIntClass = double.class 非法好了,既然拿到了 Class 对象,那我们就可以这个类的类型信息,常用的方法如下:方法用途asSubclass(Class clazz)把传递的类的对象转换成代表其子类的对象Cast把对象转换成代表类或是接口的对象getClassLoader()获得类的加载器getClasses()返回一个数组,数组中包含该类中所有公共类和接口类的对象getDeclaredClasses()返回一个数组,数组中包含该类中所有类和接口类的对象forName(String className)根据类名返回类的对象getName()获得类的完整路径名字newInstance()创建类的实例getPackage()获得类的包getSimpleName()获得类的名字getSuperclass()获得当前类继承的父类的名字getInterfaces()获得当前类实现的类或是接口类型转换检测到目前为止,我们已知的 RTTI 类型包括:传统的类型转换,如多态代表对象类型的 Class 对象RTTI 在 Java 中还有第三种形式,那就是关键字 instanceof,它返回一个布尔值,告诉我们对象是不是某个特定类型的实例,可以用提问的方式使用它if(x instanceof Dog) { ((Dog)x).bark(); }Java 还提供了 Class.isInstance() 方法动态检测对象类型,例如0 instance of String // 编译报错 String.class.isInstance(0) // 可以通过编译反射如果你不知道对象的确切类型,RTTI 会告诉你,但是有一个限制:必须在编译时知道类型,才能使用 RTTI 检测它。换句话说,编译器必须知道你使用的所有类看上去这并不是什么特别大的限制,但假设你引用了一个不在程序空间中的对象,比如你从磁盘文件或网络连接中获得大量的字节,并被告知这些字节代表一个类,那该怎么办呢?类 Class 支持反射的概念,java.lang.reflect 库中支持类 Field、Method、Constructor(每一个都实现了 Member 接口),这些类型的对象由 JVM 运行时创建,以表示未知类中的对应成员。通常我们不会直接使用反射,但反射可以用来支持其他 Java 特性,例如对象序列化等Field 代表类的成员变量(成员变量也称为类的属性),Class 类中定义了如下方法用来获取 Field 对象方法用途getField(String name)获得某个公有的属性对象getFields()获得所有公有的属性对象getDeclaredField(String name)获得某个属性对象getDeclaredFields()获得所有属性对象Field 类定义了如下方法设置成员变量的信息方法用途equals(Object obj)属性与 obj 相等则返回 trueget(Object obj)获得 obj 中对应的属性值set(Object obj, Object value)设置 obj 中对应属性值Method 代表类的方法,Class 类中定义了如下方法用来获取 Method 对象方法用途getMethod(String name, Class...<?> parameterTypes)获得该类某个公有的方法getMethods()获得该类所有公有的方法getDeclaredMethod(String name, Class...<?> parameterTypes)获得该类某个方法getDeclaredMethods()获得该类所有方法Method 类定义了如下方法对方法进行调用方法用途invoke(Object obj, Object... args)传递 object 对象及参数调用该对象对应的方法Constructor 代表类的构造器,Class 类中定义了如下方法用来获取 Constructor 对象方法用途getConstructor(Class...<?> parameterTypes)获得该类中与参数类型匹配的公有构造方法getConstructors()获得该类的所有公有构造方法getDeclaredConstructor(Class...<?> parameterTypes)获得该类中与参数类型匹配的构造方法getDeclaredConstructors()获得该类所有构造方法Constructor 代表类的构造方法方法用途newInstance(Object... initargs)根据传递的参数创建类的对象除了成员变量、方法和构造器以外,反射还能获取其他更多的信息,例如注解等,具体可查阅 Java API反射的强大威力大家已经看到了,通过反射我们甚至可以获取到一些“本不应该获取”的信息,例如程序员为了降低耦合,往往会使用接口来隔离组件,但反射却可以轻易破解public interface A {   void f(); } class B implements A {   public void f() {}   public void g() {} } public class InterfaceViolation {   public static void main(String[] args) {     A a = new B();     a.f();     // a.g(); // 编译错误     if (a instanceof B) {       B b = (B) a;       b.g();     }   } }通过使用 RTTI,我们发现 a 是用 B 实现的,只要将其转型为 B,我们就可以调用不在 A 中的方法。如果你不希望客户端开发者这样做,那该如何解决呢?一种解决方案是直接声明为实际类型,另一种则是让实现类只具有包访问权限,这样包外部的客户端就看不到实现类了除了这个以外,通过反射可以获得所有成员信息,包括 private 的,通常这种违反访问权限的操作并不是十恶不赦的,也许还可以帮助你解决某些特定类型的问题动态代理代理是基本的设计模式之一,一个对象封装真实对象,代替真实对象提供其他不同的操作,这些操作通常涉及到与真实对象的通信,因此代理通常充当中间对象。下面是一个简单的静态代理的示例:interface Interface {     void doSomething(); } class RealObject implements Interface {   @Override   public void doSomething() {     System.out.println("doSomething");   } } class SimpleProxy implements Interface {   private Interface proxied;   SimpleProxy(Interface proxied) {     this.proxied = proxied;   }   @Override   public void doSomething() {     System.out.println("SimpleProxy doSomething");     proxied.doSomething();   } } class SimpleProxyDemo {   public static void consumer(Interface iface) {     iface.doSomething();   }   public static void main(String[] args) {     consumer(new RealObject());     consumer(new SimpleProxy(new RealObject()));   } }当你希望将额外的操作与真实对象做分离时,代理可能会有所帮助,而 Java 的动态代理更进一步,不仅动态创建代理对象,而且可以动态地处理对代理方法的调用。在动态代理上进行的所有调用都会重定向到一个调用处理程序,该程序负责发现调用的内容并决定如何处理,下面是一个简单示例:class DynamicProxyHandler implements InvocationHandler {   private Object proxied;   DynamicProxyHandler(Object proxied) {     this.proxied = proxied;   }   @Override   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {     return method.invoke(proxied, args);   } } class SimpleDynamicProxy {   public static void consumer(Interface iface) {     iface.doSomething();   }   public static void main(String[] args) {     RealObject real = new RealObject();     Interface proxy = (Interface) Proxy.newProxyInstance(         Interface.class.getClassLoader(),         new Class[]{Interface.class},         new DynamicProxyHandler(real));     consumer(proxy);   } }通过调用静态方法 Proxy.newProxyInstance() 来创建动态代理,该方法需要三个参数:类加载器、希望代理实现的接口列表、以及接口 InvocationHandler 的一个实现。InvocationHandler 正是我们所说的调用处理程序,动态代理的所有调用会被重定向到调用处理程序,因此通常为调用处理程序的构造函数提供一个真实对象的引用,以便执行中间操作后可以转发请求
  • [技术干货] 2020-11-18:java中,到底多大的对象会被直接扔到老年代?
    2020-11-18:java中,到底多大的对象会被直接扔到老年代?#福大大架构师每日一题#
  • [技术干货] 【转】函数式编程:如何高效简洁地对数据查询与变换
    案例1案例一,代码摘抄来自一企业培训材料,主要代码逻辑是打印每课成绩,并找出学生非F级别课程统计平均分数:class CourseGrade {     public String title;     public char grade; }   public class ReportCard {     public String studentName;     public ArrayList<CourseGrade> cliens;       public void printReport() {         System.out.println("Report card for " + studentName);         System.out.println("------------------------");         System.out.println("Course Title       Grade");         Iterator<CourseGrade> grades = cliens.iterator();         CourseGrade grade;         double avg = 0.0d;         while (grades.hasNext()) {             grade = grades.next();             System.out.println(grade.title + "    " + grade.grade);             if (!(grade.grade == 'F')) {                 avg = avg + grade.grade - 64;             }         }         avg = avg / cliens.size();         System.out.println("------------------------");         System.out.println("Grade Point Average = " + avg);     } }成员变量采用public,缺少数据封装性没有判断cliens是否为空,可能除以0值。注:假定它不会为空,另外逻辑可能有问题,为什么统计总分是非F课程,除数却是所有课程Size,先忽略这个问题avg这个变量多个用途,即是总分,又是平均分cliens变量名难以理解!(grade.grade == 'F') 有点反直觉while循环干了两件事,打印每课的成绩,也统计了分数培训材料并未给标准解题,尝试优化一下代码,采用Java8的Stream来简化计算过程,并对代码进行了分段:public void printReport2() {         System.out.println("Report card for " + studentName);         System.out.println("------------------------");           System.out.println("Course Title       Grade");         cliens.forEach(it -> System.out.println(it.title + "    " + it.grade));           double total = cliens.stream().filter(it -> it.grade != 'F')                 .mapToDouble(it -> it.grade - 64).sum();         System.out.println("------------------------");         System.out.println("Grade Point Average = "  + total / cliens.size());     }进一步优化,把各类打印抽取各自函数: private void printHeader() {         System.out.println("Report card for " + studentName);         System.out.println("------------------------");        }       private void printGrade() {         System.out.println("Course Title       Grade");         cliens.forEach(it -> System.out.println(it.title + "    " + it.grade));     }       private void printAverage() {         double total = cliens.stream().filter(it -> it.grade != 'F')                 .mapToDouble(it -> it.grade - 64).sum();         System.out.println("------------------------");         System.out.println("Grade Point Average = "  + total / cliens.size());     }       public void printReport3() {         printHeader();         printGrade();         printAverage();     }注:如果只算非F的平均分,可以一行搞定:double avg = cliens.stream().filter(it -> it.grade != 'F').mapToDouble(it -> it.grade - 64).average().orElse(0.0d);案例二:再看一段代码:List<Integer> tanscationsIds = transcations.parallelStream()         .filter(it -> it.getType() == Transcation.GROCERY)         .sorted(comparing(Transcation::getValue).resersed())         .map(Transcation::getId)         .collect(Collectors::toList());代码非常清晰:过滤出类型为GROCERY的交易记录按其value值进行倒排序各自取其Id字段输出Id列表这看起来是不是像这样一条SQL语句:select t.id from tanscations t where t.type == 'GROCERY' order by t.value desc1.1 背后的知识目前Java8已广泛使用,对于Stream与Lambda应习以为常了,而不再是一种炫技。网上也有非常多的教程,若有同学还不熟悉他们的用法,可以多找找材料熟悉一下。Stream正如其名,像一条数据生产流水线,逐步叠加中间操作(算法和计算),把数据源转换为另一个数据集。笔者很早以前学过C#,接触过LINQ(Language Integrated Query),它比Java的Stream和Lambda用法更为清晰简洁,先给个简单示例:var result = db.ProScheme.OrderByDescending(p => p.rpId).Where(p => p.rpId > 10).ToList();LINQ为数据查询而生,可以算是DSL(Domain Specific Language)了,背后也是函数式编程(FP)一套理念,先记住其中两点:Monad 是一种设计模式,表示将一个运算过程,通过函数拆解成互相连接的多个步骤Lambda表达式 是一个匿名函数,Lambda表达式基于数学中的λ演算得名FP还有其它的特性:模式匹配,柯里化,偏函数,闭包,尾递归等。对FP感觉兴趣的同学不妨找找材料学习一下。现在的主流语言,都引入一些FP特性来提升语言在数据上的表达能力。C++11引入Lambda表达式,并提供<algorithm>,<functional>两个基础库,一个简单示例:int foo[] = { 10, 20, 5, 15, 25 };std::sort(foo, foo+5, [](int a,int b){return a > b;});Python提供functools库来简化一些函数式编程(还是相当的弱),一个简单示例:foo = ["A", "a", "b", "B"]sorted(foo, key=functools.cmp_to_key(locale.strcoll))2 函数式编程当然,面向对象语言中增加lambda这类特征不能就称为函数式编程了,大部分只不过是语法糖。是采用什么编程范式不在于语言的语法,而是在于思维方式。面向对象编程(OOP)在过去20多年非常成功,而函数式编程(FP)也不断地发展,他们相生相息,各自解决不同的场景问题:面向对象可以理解为是对数据的抽象,比如把一个事物抽象成一个对象,关注的是数据。函数式编程是一种过程抽象的思维,就是对当前的动作去进行抽象,关注的是动作。现实业务需求往往体现为业务活动,它是面向过程的,即先输入数据源,在一定条件下,进行一系列的交互,再输出结果。那面向过程与函数式的的区别是什么:面向过程可以理解是把做事情的动作进行分解多个步骤,所以有if/while这类语法支撑,走不同的分支步骤。函数式相比面向过程式,它更加地强调执行结果而非执行过程,利用若干个简单的执行单元让计算结果不断渐近,逐层推导复杂的运算,而不是像面向过程设计出复杂的执行过程,所以纯函数式编程语言中不需要if/while这类语法,而是模式匹配,递归调用等。面向对象的编程通过封装可变的部分来构造能够让人读懂的代码,函数式编程则是通过最大程度地减少可变的部分来构造出可让人读懂的代码。我们从Java的Stream实现也看到函数式的另一个特点:函数不维护任何状态,上下文的数据是不变的,传入的参数据处理完成之后再扔出来。结合上面的理解,我们可以先把世界事物通过OOP抽象为对象,再把事物间的联系与交互通过FP抽象为执行单元,这种结合或许是对业务活动的实现一种较好的解决方式。3 避免单一范式一提到编程范式,很容易联想到宗教的虔诚,每种宗教所表达信条都有一定合理性,但如果一直只遵循一种教条,可能也被让自己痛苦不堪。编程范式也是如此,正如Java在1.8之前是纯面向对象式,你就会觉得它非常繁琐。也如Erlang是纯函数式,你就会发现有时简单的逻辑处理会非常复杂。近些年来,由于数据分析、科学计算和并行计算的兴起,让人认识到函数式编程解决数据领域的魅力,它也越来越受欢迎。在这些领域,程序往往比较容易用数据表达式来表达,采用函数式可以用很少代码来实现。现实的业务软件,很多的逻辑其实也是对数据的处理,最简单是对数据的CURD,以及数据的组合、过滤与查询。所以函数式编程在许多语言中都得到支持,提升了对数据处理的表达能力。了解新的编程范式在适当的时候使用它们,这会使你事半功倍。无论什么编程范式,他们都是工具,在你的工具箱中,可能有锤子,螺丝刀…,这个工具在什么时候使用,取决待解决的问题。4 结语本文的案例只是一个引子,主要是想给你带来函数式编程的一些理念,函数式给我们解决业务问题提供了另一种思维方式:如何高效简洁地对数据查询与变换。许多语言都支持函数式一些能力,需要我们不断地学习,在合理的场景下使用他们。转自 csdn华为云
  • [技术干货] 2020-11-17:java中,吞吐量优先和响应时间优先的回收器是哪些?
    2020-11-17:java中,吞吐量优先和响应时间优先的回收器是哪些?
  • [技术干货] 成长为软件教练的三千大道之一
    本文主要介绍的是沿Java,分布式微服务架构,大数据与流计算,Linux OS与中间件,AI,这样一套功法,来讨论从一个刚毕业的理科生,如何修炼到软件教练这个层次。以及对更高层境界的畅想。师傅领进门,修行在个人。我在本文中只指出道路,相当于一次将全套功法给你。但修行的路还请自己努力。不明白的地方,Google是个金手指。我会看大家对具体哪里更感兴趣,后续将其展开讲一下,作为一个系列。大家可以留言给我。首先第一阶段,对应炼气期。你要掌握:1, Java:俗称JAVASE。不仅仅指Java语法,还包括JDK的使用。这块知识非常沉重也非常重要。沉下心花几年时间学好它。推荐学习方式:a) 《Effective Java》。让你感受下Java里面的弯弯绕绕,并不是语法表现的那样傻白甜。b) SCJP考试。现在可能改名为OCJP了也说不定。全方位让你了解Java及里面的细节。非常重要。c) 《并发编程实践》。必读刊物。多核CPU自带L2 cache却共享内存和线程,复杂的锁,一行Java代码被编译为多行机器指令而CPU在任意机器指令间都可切换线程。面对这么复杂的硬件环境,Java是如何设计保证程序正确的。2, 敏捷开发:敏捷开发不是靠书学的(虽然也有书),而是靠实践来感悟的。就像卖油翁,不去倒油光靠看老翁写的心得,永远不会倒油。3, 算法与数据结构:a) Leetcode刷题。虽然只有极少的开发会用到算法,但这是能力的体现。不要以为就是个链表反转,至少要把动态规划级别的算法搞懂。b) 《算法导论》。读读就行了。希望你能读懂。4, 测试:要了解测试同学如何写测试用例,如何保障code coverage,如何做自动化。 当上面了解的七七八八后,你自然而然就会产生心灵上的感悟从而进阶至筑基期。你要掌握:1, 设计模式:《设计模式》,Gang Of Four。四杆老枪的设计模式(我可没开车),教会你面对各种经典场景如何构造类群。2, JVM原理:《深入理解Java虚拟机》。我刚工作时,大概06年,如果那时候有人说对JVM原理很懂,那就属于国内顶尖的技术人才了。现在知识的获取方式越来越方便了,比如阅读本文。你需要了解JVM如何使用内存,如何GC,如何调整启动参数,如何查看各种dump文件等等。3, 网络编程:书籍暂时没有推荐。反正就是要搞懂HTTP/WebSocket与TCPIP与Socket的关系等知识。4, 分布式系统中各种中间件:a) Dubbo。国内最知名开源项目。无中心化分布式架构的核心。取代了IBM的SOA产品(中心化架构造成性能瓶颈)。b) ZooKeeper。Zookeeper小红书。分布式系统数据一致性协调工具。单机进程,代码执行被认为是完全可靠的,要么执行成功要么执行失败。而到分布式系统,网络调用偏多出来一个超时。分布式系统之所以比单进程复杂那么那么多,都是这独独一个超时闹的。理解CAP,理解分布式系统数据一致性,是分布式系统不出错的保障。你从来没看见银行转账时给你少转过一分钱吧?c) Kafka。《Kafka权威指南》。要理解其为什么那么快又那么可靠又那么存储空间大。同时也是理解幂等性最方便的系统。d) Redis。《Redis设计与实现》。了解了前述的知识,Redis就是个菜。无非多了个流言协议,一致性哈希环,跳跃表,哨兵,持久化方式而已。e) MySQL(假装其也是中间件好了)。《MySQL高性能》,《MySQL技术内幕:InnoDB存储引擎》。要了解红黑树和索引的实现方式,了解innodb存储引擎的工作原理,你才能更好的理解explain sql后出来的各种回显结果,帮助你更好调优sql。MyISAM被废弃了,你可以少看一本书了,偷着乐吧,少年。f) Nginx。之所以能有多个幂等节点存在,就全靠它了。学一下它的单线程技术。明明是单线程却能做到高性能。“我就是看不上你多线程,咋啦?”唯有真正理解计算机原理才能返璞归真。g) Netty。《Netty权威指南》。你有没有感觉到在2002年后的某一年,就在短短一两年内,计算机网络突然提速了?02年JDK1.4,04年Netty。本来计算机网络性能被阻塞在IO上。但NIO大幅度提升了IO效率。Go语言为什么曾那么火?它的MPG模型还是找的IO阻塞的茬,使得多线程并发会更快。学一下Linux IO模型,零拷贝技术。理解计算机原理才能做到真正性能优化。我猜测,在JDK支持了NIO之后,Tomcat等web容器很快就进行了IO模块的更新,之后各大网站的Tomcat跟着升级,于是在全世界硬件资源没变的情况下,网络站点服务器的并发响应能力大幅提升。顺便说一句为什么Java语言会长盛不衰。因为任何新语言的特性,比如Go的MPG模型,Reactive模式等,很快就会被Java抄过来。Java已有AKKA并成功用于Flink等知名项目了。而Go想抄Java的好处,短时间很难达成。h) Flume。一个日志收集传输系统。i) ProtoBuf。序列化也是性能中需要重要关注的地方。j) Tomcat。太有名了。学学其classloader的设计。5, JAVAEE依然有用的知识:比如servlet,JMX等。哎,一个时代的落幕。6, 编译原理与操作系统:我假设你上大学时候就学过了。没有的话,至少操作系统要读一下。就读清华大学的本科教材吧。7, 分布式数据库体系架构:第4条讲的是内存网络的分布式架构。这条要讲持久化存储的分布式架构。分库分表,异构索引,数据库主备等。《数据密集型系统设计》,这本书很赞,堪称存储设计的通史。8, Spirng and Mybatis:怎么说呢,你能读懂源代码当然更好。9, 前端与CDN:至少要了解一下。10,UML建模:教会你如何认识世界并转到计算机系统里来。《UML用户指南》。 上个境界,是最难晋升的了。多少开发们被阻在这步一辈子不得前进了。因为既要承担繁重的开发任务,又要学习那么多的知识,还要处理个人的生活,太难了。这些知识对你的提升又只是相加,不是相乘的关系。熬过去后海阔天空。好了你现在是金丹期了,你的很多要继续学的知识,都是靠前面给你打基础的,你会发现你的提升曲线斜率越来越抖了。你要掌握:1, 架构设计方法论:做事要有章法。《软件架构设计》。2, 领域驱动设计:软件是真实世界在计算机中的虚拟映射。如何让软件更贴近真实世界,读一下Eric Evans的《领域驱动设计》。很晦涩,不太容易懂。3, **:**这个词现在这么火,怎能不提一下。平台是啥也许你还不清楚,那就先了解一下**。4, 高性能调优:还是那句话,真正了解计算机及runtime的本质,才能做到性能调优或Hacker。《性能之巅》。5, 稳定性建设:凑合看《逆流而上》。但是稳定性和上述的性能调优,是真正体现水平的地方。还有Google的《Google SRE》。6, 两地三中心容灾系统建设:这个目前我还不清楚有什么书。如果确实没有的话,可以趁机出一本抢占市场。7, 全链路压测:又是测试。但又不仅仅是测试。对系统的性能瓶颈节点的探查,对系统QPS的掌控。单单一个起压机就不容易设计。8, 大数据:首先,你需要跨多个领域开始了解更多的知识。其次,你会发现我对技术的介绍粒度开始越来越粗了。因为你之前打的基础 - 粗粒度之下用来支撑的细粒度知识,已经生效了。再然后就是我会减少推荐书籍。到了这里你应该形成自己的知识体系了,也就会找书了。离线海量数据存储与计算的Hadoop。将Hadoop变的更易用些的HIVE。在线海量数据存储的HBase。批计算的Spark。流计算的Flink。自成一套ELK,尤其大名鼎鼎弹性搜索。时序数据库Druid。9, 数据仓库:大数据都学了,顺便也就把数仓学了呗。顺手的事而已。10,IC:HCIE,这个我就不班门弄斧了。11,网络安全:我也不懂。汗。12,Linux OS。可不仅仅是使用命令操作系统而已。当然,即使是这样也不容易了。当你还要再继续晋升,就涉及到我也不完全理解的境界了。1, 中间件的实现细节:作为业务侧的技术架构师,通常会把存储和网络的需求下压给中间件团队。但是他们是怎么实现的呢?细节重要的点是什么?2, 使用Master Slave模式,Spark等是如何实现分布式任务分解并确保计算正确的?3, Docker虚拟化技术。4, Yarn的资源分配技术。5, 计算机网络等。6, 再扩展一下技术领域,触角伸到AI领域。那么数学基础,各种论文与算法实现。又或者使用算法来赋能某个具体的业务领域比如AI赋能新零售。7, 也可以往IOT方向发展。随着5G的发展,这个应该也很火。持续看好。
  • [技术干货] Javaweb连接Mysql数据库
    大家介绍Javaweb连接Mysql数据库步骤方法及其实例,主要包括Javaweb中mysql数据库连接步骤方法及其实例使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,如有不妥之处请大佬指正!先来说说jdbc的概念JDBCJava数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法 准备工作IntelliJ IDEA mysql-connector-java-5.0.8-bin(不是最新版本)建立数据库 建表 下面说说具体的实现方法  一、直接连接主要步骤:先导包:mysql-connector-java-5.0.8-bin.jar,放在WebRoot/WEB-INF/lib/下  1.加载驱动//com.MySQL.jdbc.Driver2.获取连接 Connection对象3.获取用于向数据库发送SQL的Statement对象4.执行sql,获取数据,解析数据5.关闭连接,释放资源/*协议:子协议://主机:端口/数据库名*/ Stringurl="jdbc:mysql://localhost:3306/jdbctest"; //mysql数据库的用户名与密码,安装时自己设置,一般默认为root Stringuser="root"; Strin**word="root"; Connectionconnection=null; Statementstatement=null; ResultSetresultSet=null; try{ //1.加载驱动//com.mysql.jdbc.Driver /* *DriverManager.registerDriver(new *Driver());用这种方法会加载两次驱动,也就是说会创建两个drive对象 */ Class.forName("com.mysql.jdbc.Driver"); //2.获取连接 connection=DriverManager.getConnection(url,user,password); //3.获取用于向数据库发送SQL的Statement对象 statement=connection.createStatement(); //4.执行sql,获取数据 resultSet=statement.executeQuery("SELECT*FROMusers;"); //解析数据 while(resultSet.next()){ intid=resultSet.getInt("id"); Stringname=resultSet.getString("name"); Stringpsd=resultSet.getString("password"); Stringemail=resultSet.getString("email"); Stringbirthday=resultSet.getString("birthday"); System.out.println(id+""+name+""+psd+""+email +""+birthday); } }catch(ClassNotFoundExceptione){ e.printStackTrace(); }catch(SQLExceptione){ e.printStackTrace(); }finally{ //5.关闭连接,释放资源 if(resultSet!=null){ try{ resultSet.close(); }catch(SQLExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } resultSet=null; } if(statement!=null){ try{ statement.close(); }catch(SQLExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } statement=null; } if(connection!=null){ try{ connection.close(); }catch(SQLExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } connection=null; } /* 协议:子协议://主机:端口/数据库名 */ String url = "jdbc:mysql://localhost:3306/jdbctest"; // mysql数据库的用户名与密码,安装时自己设置,一般默认为root String user = "root"; String password = "root"; Connection connection = null; Statement statement = null; ResultSet resultSet = null; try {   // 1.加载驱动//com.mysql.jdbc.Driver   /*    * DriverManager.registerDriver(new    * Driver());用这种方法会加载两次驱动,也就是说会创建两个drive对象    */   Class.forName("com.mysql.jdbc.Driver");   // 2.获取连接   connection = DriverManager.getConnection(url, user, password);   // 3.获取用于向数据库发送SQL的Statement对象   statement = connection.createStatement();   // 4.执行sql,获取数据   resultSet = statement.executeQuery("SELECT * FROM users;");   // 解析数据   while (resultSet.next()) { int id = resultSet.getInt("id"); String name = resultSet.getString("name"); String psd = resultSet.getString("password"); String email = resultSet.getString("email"); String birthday = resultSet.getString("birthday"); System.out.println(id + " " + name + " " + psd + " " + email + " " + birthday);   } } catch (ClassNotFoundException e) {   e.printStackTrace(); } catch (SQLException e) {   e.printStackTrace(); } finally {      //5.关闭连接,释放资源   if (resultSet != null) { try {   resultSet.close(); } catch (SQLException e) {   // TODO Auto-generated catch block   e.printStackTrace(); } resultSet = null;   }   if (statement != null) { try {   statement.close(); } catch (SQLException e) {   // TODO Auto-generated catch block   e.printStackTrace(); } statement = null;   }   if (connection != null) { try {   connection.close(); } catch (SQLException e) {   // TODO Auto-generated catch block   e.printStackTrace(); } connection = null;   } }二、将数据库连接封装成一个工具类这样做的好处是,在实际开发中,就能做到,改一处即可修改全局。1.建一个名为db.properties的配置文件,放于src/url=jdbc:mysql://localhost:3306/jdbctest username=root password=root driver=com.mysql.jdbc.Driver2.工具类:importjava.io.IOException; importjava.sql.Connection; importjava.sql.DriverManager; importjava.sql.ResultSet; importjava.sql.SQLException; importjava.sql.Statement; importjava.util.Properties;  publicclassJdbcUtil{ //私有静态变量,用以读取配置文件 privatestaticPropertiesconfig=newProperties(); static{ try{ //配置资源文件 config.load(JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties")); //加载驱动 Class.forName(config.getProperty("driver")); }catch(IOExceptione){ e.printStackTrace(); }catch(ClassNotFoundExceptione){ e.printStackTrace(); } } publicstaticConnectiongetConnection(){ Connectionconnection=null; try{ connection=DriverManager.getConnection(config.getProperty("url"),config.getProperty("username"),config.getProperty("password")); }catch(SQLExceptione){ e.printStackTrace(); } returnconnection; } //用以关闭连接,释放资源 publicstaticvoidreleaseConn(Connectionconnection,Statementstatement, ResultSetresultSet){ if(resultSet!=null){ try{ resultSet.close(); }catch(SQLExceptione){ e.printStackTrace(); } resultSet=null; } if(statement!=null){ try{ statement.close(); }catch(SQLExceptione){ e.printStackTrace(); } statement=null; } if(connection!=null){ try{ connection.close(); }catch(SQLExceptione){ e.printStackTrace(); } connection=null; } }  }3.使用实例:Connectionconnection=null; Statementstatement=null; ResultSetresultSet=null; try{ //调用工具类中的静态方法来获取连接 connection=JdbcUtil.getConnection(); statement=connection.createStatement(); resultSet=statement.executeQuery("select*fromusers"); while(resultSet.next()){ intid=resultSet.getInt("id"); Stringname=resultSet.getString("name"); Stringpsd=resultSet.getString("password"); Stringemail=resultSet.getString("email"); Stringbirthday=resultSet.getString("birthday"); System.out.println(id+""+name+""+psd+""+email +""+birthday);  } }catch(Exceptione){ e.printStackTrace(); }finally{ //调用工具类中的静态方法来关闭连接,释放资源 JdbcUtil.releaseConn(connection,statement,resultSet); }每行代码都有注释,欢迎大佬提出问题哈!书山有路勤为径,学海无涯苦作舟!
  • [技术干货] java中JSONObject转换为HashMap(方法+main方法调用实例)
    1.首先要导入json相关的jar包引入的jar包:(版本自行定义,可以选用使用人数偏多的版本,这样比较稳定)commons-beanutils-1.9.2.jarcommons-collections-3.2.1.jarcommons-lang-2.6.jarcommons-logging-1.2.jarezmorph-1.0.6.jarjson-lib-2.4-jdk15.jarjar包的下载可以去下面这个网址搜索:https://mvnrepository.com/2.在Eclipse下(也可以是IntelliJ IDEA或者MyEclipse)新建package和Class(步骤略过,可自行选择名字),这里就使用jsonTest。以下代码块方法见注释,是将JSONObject转换为HashMap的主要方法,传入参数为一个JSONObject对象,返还值为一个HashMap。123456789101112//1.將JSONObject對象轉換為HashMap<String,String>public static HashMap<String, String> JsonObjectToHashMap(JSONObject jsonObj){    HashMap<String, String> data = new HashMap<String, String>();     Iterator it = jsonObj.keys();    while(it.hasNext()){        String key = String.valueOf(it.next().toString());        String value = (String)jsonObj.get(key).toString();        data.put(key, value);    }    System.out.println(data);    return data;}这个方法是将JSON字符串转换为HashMap,传入参数为一段json格式的字符串,返还一个HashMap。12345678910111213141516171819202122//2.将json字符串转换成HashMap<String,String>public static HashMap<String, String> JsonToHashMap(String JsonStrin){        HashMap<String, String> data = new HashMap<String, String>();     try{      // 将json字符串转换成jsonObject       JSONObject jsonObject = JSONObject.fromObject(JsonStrin);       @SuppressWarnings("rawtypes")        Iterator it = jsonObject.keys();      // 遍历jsonObject数据,添加到Map对象       while (it.hasNext())       {        String key = String.valueOf(it.next()).toString();         String value = (String) jsonObject.get(key).toString();          data.put(key, value);       }     }catch (Exception e) {        e.printStackTrace();        //JOptionPane.showMessageDialog(null,"ERROR:["+e+"]");    }    System.out.println(data);    return data;    }   在这里顺便介绍一下Iterator类(迭代器)迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。  Java中的Iterator功能比较简单,并且只能单向移动:  (1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。  (2) 使用next()获得序列中的下一个元素。  (3) 使用hasNext()检查序列中是否还有元素。  (4) 使用remove()将迭代器新返回的元素删除。  Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。3.直接上代码12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758package JSON; import java.util.HashMap;import java.util.Iterator;import net.sf.json.JSONObject; public class JsonTest {     public static void main(String[] args) {        JSONObject jsonObj = new JSONObject(true);        String content1 = "aaaaa";        String content2 = "bbbbb";        String content3 = "ccccc";        jsonObj.put("a", content1);        jsonObj.put("b", content2);        jsonObj.put("c", content3);        System.out.println(jsonObj.toString());        JsonObjectToHashMap(jsonObj);        String jsonstr = "{name:'王杨',sex:'男',school:'郑州航空工业管理学院'}";        JsonToHashMap(jsonstr);    }         //1.將JSONObject對象轉換為HashMap<String,String>    public static HashMap<String, String> JsonObjectToHashMap(JSONObject jsonObj){        HashMap<String, String> data = new HashMap<String, String>();         Iterator it = jsonObj.keys();        while(it.hasNext()){            String key = String.valueOf(it.next().toString());            String value = (String)jsonObj.get(key).toString();            data.put(key, value);        }        System.out.println(data);        return data;    }    //2.将json字符串转换成HashMap<String,String>    public static HashMap<String, String> JsonToHashMap(String JsonStrin){            HashMap<String, String> data = new HashMap<String, String>();         try{          // 将json字符串转换成jsonObject           JSONObject jsonObject = JSONObject.fromObject(JsonStrin);           @SuppressWarnings("rawtypes")            Iterator it = jsonObject.keys();          // 遍历jsonObject数据,添加到Map对象           while (it.hasNext())           {            String key = String.valueOf(it.next()).toString();             String value = (String) jsonObject.get(key).toString();              data.put(key, value);           }         }catch (Exception e) {            e.printStackTrace();            //JOptionPane.showMessageDialog(null,"ERROR:["+e+"]");        }        System.out.println(data);        return data;        }    }记得修改自己的package名称和 class名称。4.调用main方法测试(1)传入参数为JSONObject:输出结果为:(2)传入参数为JSON字符串:输出结果为:这里可以看到,输出的参数顺序和传入时正好相反。但是输出类型为HashMap,数据存储的格式是以key-value键值对的形式存数于HashMap中的。我们可以通过获取key值来获取到其对应的value。增加如下代码在main方法最后面:123456System.out.println("");//空格换行//通过对应的key键值,获取valueHashMap<String,String> hashmap = JsonToHashMap(jsonstr);System.out.println("--------通过遍历HashMap输出值:-------");System.out.println("name:"+hashmap.get("name")+",sex:"+hashmap.get("sex")+",school:"+hashmap.get("school"));得到如下结果:结语:到此基本的方法介绍完毕,其实是依靠了JSONObject这个对象的fromObject()方法。fromObject()方法可以转换的类型很多,可以是map、list、数组等等。运用在自己的项目中时,可以是bean或者model等自定义的类。1234567891011121314151617181920211. List集合转换成json代码List list = new ArrayList();list.add( "first" );list.add( "second" );JSONArray jsonArray2 = JSONArray.fromObject( list ); 2. Map集合转换成json代码Map map = new HashMap();map.put("name", "json");map.put("bool", Boolean.TRUE);map.put("int", new Integer(1));map.put("arr", new String[] { "a", "b" });map.put("func", "function(i){ return this.arr[i]; }");JSONObject json = JSONObject.fromObject(map); 3. Bean转换成json代码JSONObject jsonObject = JSONObject.fromObject(new JsonBean()); 4. 数组转换成json代码boolean[] boolArray = new boolean[] { true, false, true };JSONArray jsonArray1 = JSONArray.fromObject(boolArray);以上类型均可以借用fromObject()方法转换为一个JSONObject类型实例。json作为轻量级的数据格式,在前后端数据交互时很常见,每个公司应该都有自己的JSON转换方法,是公司常见的工具类。方便了随后的开发使用。
  • [技术干货] Java虚拟机使用jvisualvm工具远程监控tomcat内存
    一、配置tomcat  在tomcat的catalina.sh文件开头加上如下配置:JAVA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=192.168.184.129 -Dcom.sun.management.jmxremote.rmi.port=9999"  各参数含义:  -Dcom.sun.management.jmxremote:是否支持远程JMX访问,默认true;  -Dcom.sun.management.jmxremote.port:是JMX远程监控端口号,需要在防火墙开放该端口;  -Dcom.sun.management.jmxremote.ssl=false:表示是否对连接开启SSL加密,默认开启;  -Dcom.sun.management.jmxremote.authenticate=false :是否需要开启用户认证,默认开启,如果开启需要额外配置授权文件;  -Djava.rmi.server.hostname=192.168.184.129:远程服务器的主机名;  -Dcom.sun.management.jmxremote.rmi.port=9999:RMI端口号,JMX在远程连接时,会随机开启一个RMI端口作为连接的数据端口,可以和JMX端口号相同。二、配置主机名  使用hostname -i命令查看主机名是否为外网访问ip192.168.184.129:[root@localhost bin]# hostname -i127.0.0.1 127.0.0.1  发现是127.0.0.1,所以需要修改主机名为192.168.184.129。(1)修改/etc/sysconfig/network文件  原文件内容为:[root@localhost bin]# cat /etc/sysconfig/networkNETWORKING=yesHOSTNAME=localhost.localdomain  修改HOSTNAME为192.168.184.129,即修改后内容为:[root@localhost bin]# cat /etc/sysconfig/networkNETWORKING=yesHOSTNAME=192.168.184.129  修改后使用service network restart命令重启网络服务。(2)修改/etc/hosts文件  原文件内容为:[root@localhost bin]# cat /etc/hosts127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4::1 localhost localhost.localdomain localhost6 localhost6.localdomain6  修改127.0.0.1为192.168.184.129,并删除第二行ipv6的配置,即修改后文件内容为:[root@localhost bin]# cat /etc/hosts192.168.184.129 localhost localhost.localdomain localhost4 localhost4.localdomain4  此时使用hostname -i命令再次查看主机名,已经修改过来了[root@localhost bin]# hostname -i192.168.184.129三、配置防火墙  配置防火墙开放9999端口,编辑/etc/sysconfig/iptables文件,加入-A INPUT -m state --state NEW -m tcp -p tcp --dport 9999 -j ACCEPT,然后service iptables restart重启防火墙服务。四、配置jvisualvm  启动tomcat后,在windows本地jdk安装路径bin目录下找到jvisualvm.exe,双击打开后左侧显示如下:在“远程”上右键-->添加远程主机-->填写主机名:点击确定后,远程选项下多了一条刚才添加的主机列表。右键-->添加JMX连接,如下图,填入JMX远程连接端口号9999,并勾选“不要求ssl连接”:点击确定后,左侧多了一条pid为6822的远程连接,6822是远程tomcat的pid:双击该连接,在右侧可以动态查看jvm的概览信息,监控CPU,java堆,元空间,类,线程等数据:五、常见问题  在添加JMX连接的时候,经常会出现如下报错:此时可以从以下几个方向检查:(1)检查tomcat应用是否启动,或者修改tomcat配置后是否重启tomcat,确保9999端口处于监听状态,查看命令netstat -nl|grep 9999;(2)检查主机名是否和tomcat中配置的主机名相同,如果不同则按照第二步修改主机名;(3)检查RMI端口号端口号是否在防火墙进行了配置,如果配置的RMI端口号和JMX端口号不一致,需要在防火墙配置RMI端口号允许访问,如果没有配置,则添加-Dcom.sun.management.jmxremote.rmi.port=9999配置RMI端口号
  • [技术干货] 2020-11-12:java中as-if-serial语义和happen-before语义有什么区别?
    2020-11-12:java中as-if-serial语义和happen-before语义有什么区别?#福大大架构师每日一题#
  • [热门活动] (活动已结束)【开发者福利季】开发者身份评测认证,点亮勋章享大礼
    2020年末,华为云为开发者送福利来了!认证成为华为云开发者,开启个人技能画像,点亮开发者勋章,多重好礼等你来拿。已开启Java、Python、前端开发、API、低代码开发、敏捷教练六个通道,哪个才是你的菜,是你未来的方向。赶快来测一测吧!获奖情况将于12月15日在论坛公布,请持续关注。【活动时间】活动已结束(11月11日-12月15日)【活动内容】活动整体分三个阶段进行,认证成为华为云开发者后,专属福利逐级开启。 学习礼——争当开发者,不做尾款人 开启时间:11月11日    认证通过点亮专属勋章,开启个人技能画像。勋章查看地址:https://devcloud.huaweicloud.com/expert/assessment/skill获得会员中心200码豆,限量240000码豆,先到先得,发完即止。每个ID限领一次。码豆查看地址:https://devcloud.huaweicloud.com/bonususer/home/converge邀请5人以上(含5人)参加测评,将获得知识大礼包一份。同时获得抽奖资格,有机会获得50元京东卡和锦鲤大奖。测评完成后参与主题帖活动,还有机会获得时尚卫衣、电动牙刷等精美礼品。详情请点击链接参加:学习周 ——争当开发者,不做尾款人 抢兑礼——感恩回馈,限时兑换  开启时间:11月17日认证通过后,即可开启会员中心开发者专区优惠购资格,参与1码豆抢兑、5折/8折码豆优惠购,数量有限,先到先得。活动详情请点击:https://bbs.huaweicloud.com/forum/thread-87785-1-1.html测评完成后参与主题帖活动,还有机会获得时尚卫衣、机械键盘等精美礼品。详情请点击链接参加:抢兑周—— 感恩回馈,限时兑换更多活动信息和礼品详情,扫码可知。狂欢礼——大奖来袭,谁是锦鲤   开启时间:11月29日邀请5人以上(含5人)参与评测获得抽奖资格,将抽取幸运奖和锦鲤大奖。邀请人数统计截止于12月10日,12月14日结果公示,12月15日获奖公布。测评完成后参与主题帖活动,还有机会获得时尚卫衣、移动快充等精美礼品。详情请点击链接参加:狂欢周——大奖来袭,谁是锦鲤   (即将开启,敬请期待)【参与方式】根据自己的特长,选择下方任一测评题目,参与评测并认证通过即可参与。API测评通道Java测评通道Python测评通道前端开发测评通道低代码开发测评通道敏捷教练测评通道【活动说明】1.本次活动为华为云开发者身份测评认证,参与者首先要注册成为华为云用户,才能参与本次活动。2.活动期间,每位开发者可以多次参与答题,分数以最高成绩为准。3.每个华为云账号只能被邀请一次。4.本次活动所有回帖内容需满足华为云论坛发帖规范:https://bbs.huaweicloud.com/forum/thread-23077-1-1.html5.不得使用各类非正常渠道或方式注册账号参与,违者取消活动参与及获奖资格;获奖人收件信息与实名信息不一致者或获奖人从未参与过测评,亦不予发奖。5.获奖情况的公示和获奖通知后续会在论坛发出,请关注本帖。6.所有获奖礼品将于12月30日前寄出。7.如您在测评活动中遇到相关问题,可点击下方链接反馈,请于12月15日24时前反馈,过期反馈视为无效,望周知。 反馈链接>>8.华为云开发者生态DevCloud专家服务团队对本活动规则有最终解释权。
  • [热门活动] 【开发者福利季】开发者身份评测认证,点亮勋章享大礼(活动已结束)
    2020年末,华为云为开发者送福利来了!认证成为华为云开发者,开启个人技能画像,点亮开发者勋章,多重好礼等你来拿。已开启Java、Python、前端开发、API、低代码开发、敏捷教练等多个通道,哪个才是你的菜,是你未来的方向。赶快来测一测吧!【活动时间】2020年11月11日-2020年12月10日【活动内容】活动整体分三个阶段进行,认证成为华为云开发者后,专属福利逐级开启。 学习礼——争当开发者,不做尾款人 开启时间:11月11日    认证通过点亮专属勋章,开启个人技能画像。勋章查看地址:https://devcloud.huaweicloud.com/expert/assessment/skill获得会员中心200码豆,限量240000码豆,先到先得,发完即止。每个ID限领一次。码豆查看地址:https://devcloud.huaweicloud.com/bonususer/home/converge邀请5人以上(含5人)参加测评,将获得知识大礼包一份。同时获得抽奖资格,有机会获得50元京东卡和锦鲤大奖。测评完成后参与主题帖活动,还有机会获得时尚卫衣、电动牙刷等精美礼品。详情请点击链接参加:学习周 ——争当开发者,不做尾款人 抢兑礼——感恩回馈,限时兑换  开启时间:11月17日测评完成后参与主题帖活动,还有机会获得时尚卫衣、机械键盘等精美礼品。详情请点击链接参加:抢兑周—— 感恩回馈,限时兑换狂欢礼——大奖来袭,谁是锦鲤   开启时间:11月29日邀请5人以上(含5人)参与评测获得抽奖资格,将抽取幸运奖和锦鲤大奖。邀请点亮勋章人数排行榜的前3名获得排行奖,限量大狮运动套装、数码套装和京东卡200元奖励。测评完成后参与主题帖活动,还有机会获得时尚卫衣、移动快充等精美礼品。    活动详情请点击链接查看:狂欢周——大奖来袭,谁是锦鲤   当前论坛集赞和邀请排行榜请点击查看:排名帖链接。【参与方式】可以点击测评通道链接或者 扫描下方二维码参与测评【邀请好友方法】生成邀请链接和邀请好友参加方法如下:第一步:完成问卷填写,并提交。第二步:在问卷结束页,点击下面那个黄色按钮“邀请好友答卷 免费领取 知识大礼包”第三步:点击之后,会提示你需要在浏览器中打开分享页面,请点击右上角“...”按钮,选择“在浏览器打开”第四步:在浏览器中打开会显示如下页面,保存您的专属海报图片,分享出去即可,只要有朋友也答卷完成,即可获得相应的礼品和抽奖资格。后续也可以再打开此页面,查看你的邀请进度(页面最下方)。【活动说明】1.本次活动为华为云开发者身份测评认证,参与者首先要注册成为华为云用户,才能参与本次活动。2.活动期间,每位开发者可以多次参与答题,分数以最高成绩为准。3.每个华为云账号只能被邀请一次。4.本次活动所有回帖内容需满足华为云论坛发帖规范:https://bbs.huaweicloud.com/forum/thread-23077-1-1.html5.不得使用各类非正常渠道或方式注册账号参与,违者取消活动参与及获奖资格;获奖人收件信息与实名信息不一致者或获奖人从未参与过测评,亦不予发奖。5.获奖情况的公示和获奖通知后续会在论坛发出,请关注本帖。6.所有获奖礼品将于12月30日前寄出。7.如您在测评活动中遇到相关问题,可点击下方链接反馈,请于12月15日24时前反馈,过期反馈视为无效,望周知。 反馈链接>>
  • [调优工具] 【Hyper Tuner调优实践 03】基于Java性能分析工具的内存泄露调优实践
    1      调优概述华为鲲鹏性能优化工具是一款针对鲲鹏平台的性能调优工具,包含系统性能优化工具和Java性能优化工具。本文使用Java性能优化工具对运行中的Java程序进行了基于Profiling的GC和内存分析、结合Sampling分析,找到程序问题,并根据分析结果进行优化修改,从而实现Java程序最佳运行。2      环境要求项目说明服务器TaiShan 200 服务器(型号2280)CPU鲲鹏920 4826处理器OSCentOS 7.6应用Java应用程序性能分析工具Hyper Tuner 2.2.T2.SPC1003      前提条件1.    服务器和操作系统正常运行。2.    PC端已经安装SSH远程登录工具3.    需要优化的Java程序4      调优思路1、  检查Java程序的基础参数;2、  使用Java性能优化工具对Java进程进行GC分析以及内存分析;3、  使用Java性能优化工具对Java进程进行Sampling分析4、  针对性能的瓶颈点进行性能优化;5、  观察优化后的Java程序,判断性能是否提升5      调优过程5.1      检查Java程序的基础参数步骤1     登录Java性能优化工具步骤2     创建Guardian (说明:部署的需要优化的Java进程的服务器)步骤3     启动Profiling分析获取到的Java程序的基础参数如下图:只配置最大堆大小可继续通过工具其他功能分析5.2      查看Profiling概览概览分析:通过概览功能页面查看Java进程发现内存占用很高、GC活动也频繁5.3      查看Profiling GC步骤1     点击页面上方的【GC】页签步骤2     查看GC的活动详情GC分析:发现在几分钟内多次出现old GC,后续old GC频繁old GC 频繁的原因分析:5.4      查看Profiling内存转储该Java进程的内存在old GC之后回收的内存较少,且频繁GC,继续使用工具其他功能分析步骤1     页面上方的【内存转储】页签步骤2     等待执行内存转储的结果内存转储分析:下图为内存转储的【直方图】,展示了Java进程中堆内存分配,可以发现第一行的Object[] 与其他数据的浅堆大小不在一个数量级,此时需要结合支配树继续分析 支配树分析:下图中的第一行非常直观的可以发现该ScheduleTask类的浅堆大小占据了整个堆的98.27%,继续查看该类的下级支配数据,最终发现该类支配了大量的Object[]类,Object[]类下支配最多的即Student类5.5      优化 Java程序分析:通过上述四步骤的Profiling分析,可以发现堆内存被大量的ScheduleTask类支配的Student类所占据,因此回归Java程序本身发现该ScheduleTask类是一个作为缓存功能的类,自己检视代码发现该类使用的HashMap作为缓存对象,在构建代码时忽略了缓存的过期时间,导致历史的数据一直在该缓存对象中导致内存泄露,GC无法回收对象。优化:       优化代码,加入缓存过期策略;5.6      优化后的 Java程序优化后的程序通过概览页即可发现内存使用正常、GC活动正常6      实践总结本次实践中,对一Java程序进行了性能分析,通过Profiling GC分析和内存转储分析发现了程序中的内存泄漏点,进而优化程序中的内存泄漏点达到优化程序性能的目的,解决了程序中内存持续占满且频繁old GC的问题。在进行其他程序调优时,需要根据华为鲲鹏性能优化工具采集分析的实际结果和对应的优化建议进行调优操作。具体的调优思路可以参考本次实践。
  • [技术干货] 2020-11-04:java里,总体说一下集合框架。
    2020-11-04:java里,总体说一下集合框架。#福大大架构师每日一题#
  • [互动交流] obs的.net版本的代码为何报错??但用同样的java代码却是正常执行。
    请教一个问题,需要华为专业的帮助:我要遍历所有桶名,直接用官方提供obs的API代码,复制粘贴,然后直接运行就报错。错误是在huaweicloud-sdk-dotnet-obs-master源代码里抛出的。需要说明的是:这个.net版本的代码,在连接了互联网的机器上能够正常执行,是不会报错的。但是,由于我们的内网服务器不能连接互联网,是通过专线IPsec来实现对华为云的连接(在此条件下用obs客户端可以连接上并能正常操作云上的对象),并且用obs的java版本的代码也是可以正常执行。但是用obs的.net版本的程序执行却会报错!百思不得其解。报错情况,如下图:我调用执行的API代码,如下图:
  • [技术干货] 用IDEA构建一个简单的Java程序范例
    一、创建项目1.点击菜单栏File->New->Project...2.从左边栏找到Java,例如我这里是Java Enterprise(每个人的可能不一样,因为IDE版本可能不同),然后选择project SDK,没有的话点击Download JDK...,有的话点击Add JDK...3. Download JDK是这个界面,Vendor我这里选择Oracle OpenJDK(各位可以根据需要选择),Version是版本,Location是位置4.下载或者添加之后,点击Next,这里可以选择Specification和Implementation,大家根据需要选择,我这里直接Next5.创建项目和名称二、编写代码1.项目结构如下2.我们打开src的main,右键点击main里的java,选择New->Package,输入包的名字,我这里是Hello3.新建一个class,输入名字,我这里是Hello4.输入代码package Hello; public class Hello { public static void main(String []args){ System.out.println("Hello!"); } }
总条数:2294 到第 页
上滑加载中