Java知识点更新...

本文是记录自己慢慢积累的Java知识点, 后续会慢慢更新, 欢迎给我留言指导, 我会用心写好每篇文章与你分享.

1.==与equals的区别:

==是直接比较的两个对象的内存地址

基本数据类型和String作为常量在方法区中的常量池里面以HashSet策略存储起来,在常量池中,一个常量只会对应一个地址, 所以第一个为true不难理解

Integer 在常量池中的存储范围为[-128,127] , 128这个值不在这个范围, 会在堆内存中创建一个新的对象来保存这个值, 在堆中存储是用内存地址引用指向值, 所以第二个结果为false

下面摘录有equals底层源码, 看下得知, 在Object类型的equals方法是直接通过来比较的,在没有重写该方法时, 和是没有任何区别, 所以第四个为true, 值相等

Q和W是new出来的实例对象, 在堆内存中以地址值存储, 第五个为false, 第六个比对的比对的依然是长量值, 为true.

经测试, 区别就很明显了: ==是比较的两个对象的内存地址, equals可以重写, 传参数是地址值就比较地址值, 传参比较的是值就比较值, 有自己定义决定

/**
 * @author Jeady
 * @Date 2020/2/8
 */
public class EqualsTest {
    public static void main(String[] args) {
        Integer a1 = 127;
        Integer b1 = 127;
        System.out.println(a1==b1);//true

        Integer a2 = 128;
        Integer b2 = 128;
        System.out.println(a2==b2);//false
        System.out.println(a2.equals(b2));//true

        Q q = new Q();
        W w = new W();
        System.out.println(q.equals(w));//false
        System.out.println(q.a.equals(w.b));//true
    }
}
class Q{
    Integer a = -128;
    @Override
    public boolean equals(Object w) {
        return a.equals(w);
    }
}
class W{
    Integer b = -128;
}

2.equals底层源码:

    /**
     * Compares this object to the specified object.  The result is
     * {@code true} if and only if the argument is not
     * {@code null} and is an {@code Integer} object that
     * contains the same {@code int} value as this object.
     *
     * @param   obj   the object to compare with.
     * @return  {@code true} if the objects are the same;
     *          {@code false} otherwise.
     */
    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

3.String, StringBuffer, StringBuilder的区别:

1.String是字符串常量,其他两者属于字符串变量,String对象创建后不可以改变,对String的操作实际上是不断创建和回收的过程,执行速度慢
2.StringBuilder是线程不安全的,而StringBuffer是线程安全的
3.String适用于少量的字符串操作;StringBuilder适用于单线程下的在字符串缓冲区进行大量的操作的情况下;StringBuffer适用于多线程下的在字符串缓冲区进行大量的操作的情况下。

4.ArrayList,LinkedList的区别:

1.ArrayList以索引对应的元素(可随机访问),有索引访问速度就快,LinkedList需遍历整个链表来获取对应的元素。
2.ArrayList的底层是数组,增删需要复制和移动数组实现, LinkedList的底层是双向链表,只需要修改对应的指针即可,增删速度更快
3.但是, 如果增删在末尾(调的是remove()和add()方法), 数据量有百万级别了, ArrayList更快, 同理如果增删在中间位置较多,同时数据量也到了百万级别,Array List的性能会更高, ArrayList的消耗主要是在移动和复制上, 而LinkedList的遍历速度是要慢于ArrayList的复制移动速度的

5.HashMap和HashTable的区别

1.都是使用key-value的形式来存储数据,区别是HashTable基于Dictionary类,而HshMap是基于abstractMap。
2.HashMap是单线程安全的,HashTable是多线程安全的, 我们一般更多的用ConcurrentHashMap来支持多线程安全
3.HashMap仅仅支持Iterator的遍历方式,HashTable支持Iterrator和Enumeration两种遍历方式
4.HashMap可以允许存在一个为null的key和若干个为null的value,但是HashTable中的key和value都不允许为null

6.MySql分页:

Limit [offset, row]: offset指定要返回的第一行的偏移量(索引号),rows第二个指定返回行的最大数目。初始行的偏移量为0

公式:start=(currentPage-1)*pageSize

7.类加载机制:

1.系统通过加载、连接、初始化三个步骤对类进行初始化;
2.类的加载:是指将类的class文件加载进内存,并创建一个java.lang.Class对象
3.类加载器由系统提供,通常称为系统加载器,可以通过继承ClassLoader积累来创建自己的类加载器。
4.类的连接:把类的二进制数据合并到JRE中;分为三个阶段:
(1)验证:检验被加载的类是否有正确的内部结构,并且和其他类协调一致;
(2)准备:为类的类变量分配内存,设置默认初始值;
(3)解析:将二进制中的符号引用替换成直接引用;
5.类的初始化:虚拟机扶负责对类进行初始化,对类变量进行初始化

8. ConcurrentHashMap的实现原理

线程安全并且高效的HashMap
锁分段技术:将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一段数据的时候,其他段的数据也能被其他线程访问;
JDK1.7
ConcurrentHashMap的数据结构是由一个Segment数组和多个HashEntry组成;采用了分段锁的技术;
JDK1.8
Node数组+链表+红黑树的数据结构;并发控制使用Synchronized和CAS来操作;(红黑树是为了提高查找效);
将Node的value和next加上volatile来保持可见性和禁止重排序;(只允许对数据进行查找,不允许进行修改);

Node:Node是ConcurrentHashMap存储结构的基本单元,继承于HashMap中的Entry,用于存储数据;

在ConcurrentHashMap中,初始化操作并不是在构造函数实现的,而是在put操作中实现;

9. Sleep、yield、wait、join方法的区别

Sleep:在指定时间内让当前正在执行的线程暂停执行,但不释放锁;
Yield:暂停当前正在执行的线程,不释放锁;使线程重新回到可执行状态;(会出现yield的线程可能进入到可执行状态后,当场抢到cpu资源,又被执行,甚至,无限连任)
Wait:调用该方法,使线程处于阻塞状态,需调用notify或notifyAll方法唤醒;在等待中会释放锁;
Join:等待调用join方法的线程结束后,在继续执行下面的代码;

Redis缓存和数据库的数据不一致怎么解决

Mysql binlog 增量发布订阅消费+消息队列+增量数据更新到redis
1) 读请求走Redis:热数据基本都是在Redis;
2) 写请求走Mysql:增删改都操作Mysql;
3) 更新redis数据:mysql的数据操作binlog,来更新redis;

2.更新Redis
1)数据操作主要分为两块:
A.一个是全量(将全部数据一次写入到redis)
b.一个是增量(实时更新)
这里的增量,指的是mysql的update、insert、delete变更数据

这样一旦mysql中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至redis,redis在根据binlog中的记录,对redis进行更新,就无需再业务线去操作缓存内容;

8.垃圾收集器:

GC的常见算法:
主要有标记-清除算法,标记-压缩算法,复制算法,分代收集算法, 目前最主流的是分代收集算法

1.标记-清除算法是为每个对象存储一个标记位,记录对象的状态(活着或是死亡). 分为两个阶段,一个是标记阶段,这个阶段内,为每个对象更新标记位,检查对象是否死亡;第二个阶段是清除阶段,该阶段对死亡的对象进行清除,执行 GC 操作。

2.标记-压缩法是标记-清除法的一个改进版, 不同的是,在第二个阶段,该算法并没有直接对死亡的对象进行清理,而是将所有存活的对象整理一下,放到另一处空间,然后把剩下的所有对象全部清除

3.复制算法: 该算法将内存平均分成两部分,然后每次只使用其中的一部分,当这部分内存满的时候,将内存中所有存活的对象复制到另一个内存中,然后将之前的内存清空,只使用这部分内存,循环下去

串行垃圾收集器(Serial)

单线程一个收集器,JVM在发现我们内存不够用的时候就会暂停应用程序的执行。开启一个垃圾回收线程来回收垃圾,一般适用于小的嵌入式设备

并行垃圾收集器(Parallel)

垃圾收集线程之间并行,但它们和用户线程并不是并行的。多条垃圾收集线程并行工作时,用户线程仍然处于等待状态。即内存不够的时候暂停应用程序,启动多个垃圾收集线程做垃圾回收,回收完重新启动应用程序。适合那种科学计算比如说模型运算、后台处理这样的弱交互场景,也就是不需要实时交互的那种场景。(吞吐量优先)

并发垃圾收集器(Concurrent)
垃圾收集线程和用户线程之间是并行的,用户线程和垃圾收集线程同时执行(不能说完全同时,可能是交替执行),垃圾收集线程工作的时候不会停顿用户程序正常运行,适用于对响应时间有要求并且交互性较强的场景(响应时间优先)(如:Web)

在JDK8里有两种并发垃圾收集器:CMS 和 G1
CMS: 一种老年代垃圾收集器,其特点是响应时间优先,低延迟,低停顿
CMS的缺点

  1. CPU敏感:当启用一个线程去进行垃圾回收,那么现在就只有这一个线程,一个CPU可以去响应垃圾的回收

  2. CMS会产生浮动的垃圾:CMS在做垃圾回收的时候,应用程序也在运行,所以有可能产生新的垃圾,需要等到下一次GC才能清除。成为浮动垃圾。

  3. 有可能物理不连续产生空间碎片

G1收集器就是适用于大内存并且停顿时间非常小,如:大于6G的内存并且停顿时间小于0.5s

G1的堆结构逻辑上也是Old(老年代)和Young(新生代)

GC调优参数:

停顿时间:
垃圾收集器做垃圾回收时需要中断应用程序的时间。由参数 -XX:MaxGCPauseMillis决定

吞吐量:
在垃圾收集上的耗时与在应用上的耗时的占比。由参数 -XX:GCTimeRatio=决定,比如设置n为 10,那么垃圾收集的时间的比重为 1 / 10 + 1 = 1 / 11

GC的过程:

1.初始创建对象的时候,对象放在Eden中
	 若是大对象则直接进入Old(老年代),对大对象的定义依赖于JVM的一个参数:-XX:PretenureSizeThreshold
2.随着时间的流逝,Eden种存放的对象越来越多,当Eden区域满了,会进行minor GC,会将Eden种还在使用的对象放入到servivor0中,不需要的对象清楚掉.清除掉之后的Eden就变空了
3.Eden中有可以重新接纳对象,随时间的流逝,Eden中存放的对象越来越多,当Eden区域满了,又进行GC ,会将Eden与servivor中还在使用的对象放入到survivor1中,Eden与servivor中使用的对象清除掉
4.循环第三个步骤
5.当survivor中空间不足,会将还在使用的对象放入到老年代中
6.循环3-5步骤
7.随着时间流逝,老年代中空间不足,这时候就需要full GC , Full GC的时间短则几分钟,长的十几分钟.期间,进行对暂停一切操作,优先GC, 这个时候可能还会出现拉取shuffle数据失败

如果在GC的时候拉取shuffle数据失败,会有一个重试次数,如果重试之后,任然没有拉取到数据,任务报错,停止执行
针对这个问题,可以调整拉取shuffle失败的参数:
spark.shuffle.io.maxRetries=6 shuffle拉取数据失败的时候最大重试次数
spark.shuffle.io.retryWait=10s拉取失败的时候,每次重试的时间间隔

在这里插入图片描述

什么时候选择G1收集器?

  1. 50%以上的堆被存活对象占用

  2. 对象分配和进入Old(老年代)的速度变化很大

  3. 垃圾回收时间很长,超过1s

垃圾收集器的选择:

Young(新生代)和Old(老年代)可以采用不同的垃圾收集器,可以搭配使用,JDK8推荐使用G1性能高

1、调整堆内存大小让服务器自行选择

2、内存小于100M使用串行收集器

3、单核并没有停顿时间需求使用串行或者JVM自己选择

4、能接受停顿时间超过1秒,选择并行垃圾收集器或者JVM自己选择

5、若响应时间最重要,尽量不超1s(反正响应越快越好),使用并发垃圾收集器

Server模式与Client模式
JVM如果不显式指定是Server模式还是Client模式的话,虚拟机启动检测主机是否为服务器,如果是,则以Server模式启动,否则以client模式启动
Server模式启动时,速度较慢,但是一旦运行起来后,性能将会有很大的提升。
Java - version: 查看运行模式

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"Java高级架构面试知识点整理.pdf"是一份关于Java高级架构的面试知识点的文档。该文档主要包括以下几个方面的内容: 1. Java多线程和并发:讲解Java的多线程概念、线程安全性、线程的生命周期和状态转换、线程同步与锁、并发工具类(如CountDownLatch、Semaphore等)、线程池等相关知识点。 2. JVM与GC算法:了解Java虚拟机(JVM)的基本原理、内存结构和内存模型,理解垃圾回收(GC)算法的原理和常见的垃圾回收器(如Serial、Parallel、CMS、G1等),掌握GC调优的一般方法。 3. 分布式架构和并发编程模型:认识分布式系统的基本概念、CAP定理、分布式存储和分布式计算的方案,了解常见的并发编程模型(如Actor模型、异步编程等)和实现方式。 4. 高性能网络编程:熟悉Java NIO的基本原理、底层实现和使用方式,了解Java网络编程的相关API和概念(如Socket、ServerSocket、Selector等),了解基于Netty框架的高性能网络编程。 5. 分布式消息队列和间件:了解消息队列的基本概念、常见的消息间件(如RabbitMQ、Kafka等)的特点和使用场景,理解消息队列的高可用、持久化、消息顺序等特性。 6. 微服务和服务治理:理解微服务的概念、优劣势和架构特点,了解微服务的拆分和组织原则,熟悉常见的服务治理框架(如Spring Cloud、Dubbo等)和相关的技术组件。 7. 高可用和容灾设计:掌握高可用架构的设计原则和常见的高可用技术方案(如集群、负载均衡、故障切换等),了解容灾方案的设计和实现方法,学习如何保证系统的可靠性和稳定性。 8. 性能优化与调优:了解性能优化的基本思路和方法,熟悉性能调优的一般流程和工具,掌握常见的性能调优技术(如缓存、异步、批处理等)和优化手段。 以上就是对于"Java高级架构面试知识点整理.pdf"文档的简要回答,希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值