Java入门,最全面最简单的Java基础教程

Java是一种跨平台的语言,一次编写,到处运行,在世界编程语言排行榜中稳居第二名(第一名是C语言)。

Java用途广泛,可以用来开发传统的客户端软件和网站后台,也可以开发如火如荼 Android 应用和云计算平台。

为初学者而著!

适合零基础的小伙伴们学习。

感兴趣的小伙伴可以点视频链接和小编一起编程哟,共同进步!

<对零基础学习者的建议>

1. 看视频学习,不要看书学习。很多人都说看视频慢,建议直接看优秀的书籍,所以我就买了C语言的一些书和Java的一些书(都是初学入门的),但都看不懂,看不下去。反而是后期跟着视频学习一段时间后,再翻开书本(其实几乎没看过书),慢慢能知道书里在讲什么了。大家千万不要觉得看视频会显得自己学习能力不够强。实际上,大学选择计算机专业的同学,又有多少比例是不靠老师上课,自己躲图书馆把编程学会的呢?从这个角度来说,看视频相当于大学课堂听课。并没什么不妥。

2. 不懂的知识点视频多看几遍,如果视频有配套笔记,第二天起来复习一遍,加深印象。自己也可用word做笔记,写学习日志。JavaSE有不懂的,可以百度或谷歌,看看别人的技术博客。再回过头看视频可能就突然明白了。因为我也这么试过,对我帮助很大,希望你也能试试。

3. 根据视频内容画思维导图!

理清讲解思路,让自己有全局观。初学Java,每一天的视频刚听完就基本忘得差不多了。很多知识点脑海中也只剩下一个名词,具体讲了什么已经记不得!做笔记长远来看是最省时间的。因为笔记内容都是自己消化过的,后期不用再去看视频复习(太麻烦了),直接看自己的笔记效率更高!反而蜻蜓点水,不做笔记一味求快的人,学到后面跟不上。因为这些知识点你只是听懂了,而不是理解,也没有实际编码操作过,印象是不深的!!

方便日后复习,以及遗忘时的检索回忆。

思维导图要自己做,自己看,效果最好。看别人的基本没效果。

4. 初级阶段不建议买任何书籍,专心看视频和附带的笔记足够了。对零基础的学习者来说,JavaSE的学习非常困难。之前在面向对象一章就已经很崩溃,哪知异常也这么抽象,完全不知道它是干嘛的….很多人是科班出身,早就忘了当初自己连软件都不会装的窘境。就像我们现在根本不会觉得用筷子还需要学习,但你爸妈当年为了教你用筷子,可是头疼过不止一次呢!

按照后面JavaWeb的学习来看,我的建议是:

面向对象是基石,JavaSE中最重要的一是集合,二是IO,希望大家学习这两个知识点时认真对待,多敲代码,多思考。

常用API里,String及其相关类StringBuilder, StringBuffer等必须熟悉,后面会不断用到。不学好的话,后面怎么死都不知道!

泛型一般只出现在集合中,个人觉得如果一时无法掌握,那么暂时会在集合中使用泛型就行了。

反射对于初学者来说是非常抽象的!!但它又无比重要。它虽然不是JavaSE的重点,但是它是JavaWeb很多难点的底层支撑,不懂反射,寸步难行。

java中集合的集合类主要由两个接口派生而出:Collection和Map;这两个接口是java集合框架的根接口,这两个接口下,又包含了一些子接口和实现类。

分享:百度云Java三面,面试题及答案

1、首先是项目部分,问的比较细。这部分没什么参考价值,忽略。

2、如果一个对象有多个方法加了synchronized,那么该对象有几把锁对象锁是在一个类的对象上加的的锁,只有一把,不管有几个方法进行了同步。这些同步方法都共有一把锁,只要一个线程获得了这个对象锁,其他的线程就不能访问该对象的任何一个同步方法。

3.NIO与AIO的区别以及各自的作用Java NIO :同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器。AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器。

4.IOC的实现原理Spring的IOC实现原理就是工厂模式加反射机制,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象,这种编程方式可以让对象在生成时才被决定到底是哪一种对象。把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言提供的反射机制,根据配置文件中给出的类名生成相应的对象。Spring支持三种依赖注入方式,分别是属性(Setter方法)注入,构造注入和接口注入。

5、反射的原理反射首先是能够获取到Java中的反射类的字节码,然后将字节码中的方法,变量,构造函数等映射成 相应的 Method、Filed、Constructor 等类

6、数据库调优思路的思路。1.慢查询的开启并捕获2.explain+慢sql分析3.show profile查询sql在mysql服务器里面的执行细节和生命周期情况4.sql数据库服务器的参数调优7.开放性的问题,如何提高系统QPS。

这个问题我感觉大致可以从这几个方面1、单机版能承受并发的能力是有限的,我们可以进行系统拆分,分开部署在不同的机器上。2、用消息队列削峰。系统不至于因为瞬间的流量挂掉。并且可以配合使用限流与服务降级。3、用redis什么的做缓存。4、数据库分库分表,建立合适的索引。

首先还是怼项目。问的比较细,有时候面试官会把条件改下,问假如现在需要你实现这个功能,你怎么来实现?中间也会穿插一些中间件和基础原理的问题。

1、redis做分布式锁怎么做的?先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止由于程序crash等原因没有释放。最后线程操作结束之后,释放分布式锁。

2、Redis能做分布式锁的原理?Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。

3、JUC下面主要用哪些东西?CountDownLatch、Cyclicbarrier 。。。。。等等。其核心是AQS

4、说一下AQS?AQS是JUC中很多同步组件的构建基础,简单来讲,它内部实现主要是状态变量state和一个FIFO队列来完成,同步队列的头结点是当前获取到同步状态的结点,获取同步状态state失败的线程,会被构造成一个结点(或共享式或独占式)加入到同步队列尾部(采用自旋CAS来保证此操作的线程安全),随后线程会阻塞;释放时唤醒头结点的后继结点,使其加入对同步状态的争夺中。

AQS为我们定义好了顶层的处理实现逻辑,我们在使用AQS构建符合我们需求的同步组件时,只需重写tryAcquire,tryAcquireShared,tryRelease,tryReleaseShared几个方法,来决定同步状态的释放和获取即可,至于背后复杂的线程排队,线程阻塞/唤醒,如何保证线程安全,都由AQS为我们完成了,这也是非常典型的模板方法的应用。AQS定义好顶级逻辑的骨架,并提取出公用的线程入队列/出队列,阻塞/唤醒等一系列复杂逻辑的实现,将部分简单的可由使用者决定的操作逻辑延迟到子类中去实现。

网上很多博客,不了解的可以去找找看。

5、ReentrantLock非公平锁和公平锁的实现原理?

项目部分就不具体说了。问了怎么排查问题,都遇到哪些难题什么的。 1、redis分布式锁如何保证原子性? 可以了解下这个命令:set key value [EX seconds] [PX milliseconds] [NX|XX]

2、用过ThreadLocal吗?简单说一下? ThreadLocal采用的是以空间换时间的方式,为每个线程提供一份变量副本。每一个线程都可以独立的改变自己的副本。具体例子可以自己去网上找。

3、Java8之后的ConcurrentHashMap, 舍弃分段锁 通过 JDK 的源码和官方文档看来, 他们认为的弃用分段锁的原因由以下几点: 1)加入多个分段锁浪费内存空间。 2)生产环境中, map 在放入时竞争同一个锁的概率非常小,分段锁反而会造成更新等操作的长时间等待。 3)为了提高 GC 的效率。

4、介绍下cms收集器 CMS收集器是老年代收集器,可以配合新生代的Serial和ParNew收集器一起使用。使用的是标记清除算法,容易产生内存碎片。 4个步骤: 1.初始标记–》并发标记–》重新标记–》并发清除 (初始标记、重新标记)仍需STW。但初始标记仅仅只标记了一下GC Roots能直接关联到的对象,速度很快。 而重新标记则是修正并发标记期间因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,虽然一般比初始标记阶段稍长,但要远小于并发标记时间。

5、redis缓存与数据库一致性问题? 一致性问题主要出现在数据更新的时候,通常在更新时采取删除缓存而不是更新缓存。 具体一点?先淘汰缓存,再写数据库。因为如果先写数据库可能出现如果有读请求发生,可能导致旧数据入缓存,引发数据不一致。

6、dubbo有哪几种负载均衡策略? 1.RandomLoadBalance:按权重随机调用,这种方式是dubbo默认的负载均衡策略 2.RoundRobinLoadBalance:轮询,按公约后的权重设置轮询比率 3.LeastActiveLoadBalance:最少活跃次数 4.ConsistentHashLoadBalance:一致性hash 5.自定义负载均衡策略

7、介绍下一致性hash? 先说下普通hash有机器宕机或者新加机器的后果。然后 介绍一致性hash。 hash值是个整数非负数值,所有的hash值形成一个闭圆环 对集群的的节点的某个属性求hash值,放到环上 数据key求hash值,也放到环上。 数据的hash值按顺时针找到离它最近的节点,放在该节点上。

8、介绍下mysql的回表和覆盖索引? 回表简单来说就是数据库根据索引(非主键)找到了指定记录所在行后,还需要根据主键再次到数据库里获取数据。 如果一个索引包含(或覆盖)所有需要查询的字段的值,称为‘覆盖索引’。即只需扫描索引而无须回表。

9、说下模板方法模式? 所谓模版方式模式:把不变的行为搬到超类,去除子类中重复的代码来体现他的优势;当不变的和可变的行为在子类实现中混合在一起的时候, 不变的行为就会在子类中重复实现,我们通过模板方法模式把这些行为搬移到单一的地方,这样就可以帮助子类摆脱重复不变行为的纠缠。

最后,分享一份进阶宝典《Java核心知识点整理.pdf》,覆盖了JVM、锁、高并发、反射、mybatis、Spring原理、微服务、Zookeeper、数据库、数据结构等等,获取请关注后私信本头条号: Java 即可免费获取!

百度java面试真题

1、SpingBoot 也有定时任务?是什么注解?

在 SpringBoot 中使用定时任务主要有两种不同的方式,一个就是使用 Spring 中的@Scheduled 注解,另一个则是使用第三方框架 Quartz。

使用 Spring 中的 @Scheduled 的方式主要通过 @Scheduled 注解来实现。

使用 Quartz ,则按照 Quartz 的方式,定义 Job 和 Trigger 即可。

2、请描述线程的生命周期,它们之间如何切换?

线程的生命周期包含 5 个阶段,包括:新建、就绪、运行、阻塞、销毁。

◆ 新建(NEW):就是刚使用 new 方法,new 出来的线程;

◆ 就绪(RUNNABLE):就是调用的线程的 start()方法后,这时候线程处于等待 CPU 分配资源阶段,谁先抢的 CPU 资源,谁开始执行;

◆ 运行(RUNNING):当就绪的线程被调度并获得 CPU 资源时,便进入运行状态,run 方法定义了线程的操作和功能;

◆ 阻塞(BLOCKED):在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如 sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用 notify 或者 notifyAll()方法。唤醒的线程不会立刻 执行 run 方法,它们要再次等待 CPU 分配资源进入运行状态;

◆ Waiting(无限等待):一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进 入 Waiting 状态。进入这个状态后不能自动唤醒,必须等待另一个线程调用 notify 方法或者 notifyAll 方法时才能够被唤醒。

◆ 销毁(TERMINATED):如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源;

3、什么情况线程会进入 WAITING 状态?一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入 Waiting 状态。进入这个

状态后不能自动唤醒,必须等待另一个线程调用 notify 方法或者 notifyAll 方法时才能够被唤醒。

◆ 调用 Object 对象的 wait 方法,但没有指定超时值。

◆ 调用 Thread 对象的 join 方法,但没有指定超时值。

◆ 调用 LockSupport 对象的 park 方法。

4、简述多进程开发中 join 和 deamon 的区别?

join:当子线程调用 join 时,主线程会被阻塞,当子线程结束后,主线程才能继续执行。

deamon:当子进程被设置为守护进程时,主进程结束,不管子进程是否执行完毕,都会随着主进程的结束而结束。

5、异步和同步、阻塞和非阻塞之间的区别?

同步

当一个 request 发送出去以后,会得到一个 response,这整个过程就是一个同步调用的过程。哪怕 response 为空,或者 response 的返回特别快,但是针对这一次请求而言就是一个同步的调用。

异步

当一个 request 发送出去以后,没有得到想要的 response,而是通过后面的 callback、状态或者通知的方式获得结果。可以这么理解,对于异步请求分两步:

◆ 调用方发送 request 没有返回对应的 response(可能是一个空的 response);

◆ 服务提供方将 response 处理完成以后通过 callback 的方式通知调用方。

对于 1)而言是同步操作(调用方请求服务方),对于 2)而言也是同步操作(服务方回掉调用方)。从请求的目的(调用方发送一个 request,希望获得对应的 response)来看,这两个步骤拆分开来没有任何意义,需要结合起来看,而这整个过程就是一次异步请求。异步请求有一个最典型的特点:需要 callback、状态或者通知的方式来告知调用方结果。

阻塞

阻塞调用是指调用方发出 request 的线程因为某种原因(如:等待系统资源)被服务方挂起,当服务方得到 response 后就唤醒挂起线程,并将 response 返回给调用方。

非阻塞

非阻塞调用是指调用方发出 request 的线程在没有等到结果时不会被挂起,并且直到得到response 后才返回。

阻塞和非阻塞最大的区别就是看调用方线程是否会被挂起。

6、为什么要分内核态和用户态?

假设没有这种内核态和用户态之分,程序随随便便就能访问硬件资源,比如说分配内存,程序能随意的读写所有的内存空间,如果程序员一不小心将不适当的内容写到了不该写的地方,就很可能导致系统崩溃。用户程序是不可信的,不管程序员是有意的还是无意的,都很容易将系统干到崩溃。

正因为如此,Intel 就发明了 ring0-ring3 这些访问控制级别来保护硬件资源,ring0 的就是我们所说的内核级别,要想使用硬件资源就必须获取相应的权限(设置 PSW 寄存器,这个操作只能由操作系统设置)。操作系统对内核级别的指令进行封装,统一管理硬件资源,然后向用户程序提供系统服务,用户程序进行系统调用后,操作系统执行一系列的检查验证,确保这次调用是安全的,再进行相应的资源访问操作。**内核态能有效保护硬件资源的安全。

7、说下类加载器与类加载?加载的类信息放在哪个区域?

一个类型从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期将会经历加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)七个阶段。其中验证、准备、解析三个部分统称为连接(Linking)。

Java 虚拟机设计团队把类加载阶段中“通过一个类的全限定名来获取描述该类的二进制流”这个动作放到 Java 虚拟机外部去实现。比便让程序应用自己决定如何取获取所需的类。实现这个动作的代码被称为“类加载器”(Class Loader)。

对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在 Java 虚拟机

中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。

8、UDP 协议和 TCP 协议的区别?

◆ TCP 基于连接,UDP 基于无连接

◆ TCP 要求系统资源较多,UDP 较少

◆ UDP 程序结构较简单

◆ TCP 保证数据正确性,UDP 可能丢包

◆ TCP 保证数据顺序,UDP 不保证

9、limit 1000000 加载很慢的话,你是怎么解决的呢?

方案一:如果 id 是连续的,可以这样,返回上次查询的最大记录(偏移量),再往下 limit

select id,name from employee where id>1000000 limit 10.

方案二:在业务允许的情况下限制页数:

建议跟业务讨论,有没有必要查这么后的分页啦。因为绝大多数用户都不会往后翻太多页。

方案三:order by + 索引(id 为索引)

select id,name from employee order by id limit 1000000,10方案四:利用延迟关联或者子查询优化超多分页场景。(先快速定位需要获取的 id 段,然后再关联)

SELECT a.* FROM employee a, (select id from employee where 条件 LIMIT 1000000,10 ) b where a.id=b.id

10、MySQL 的索引分类是什么?

单列索引

◆ 普通索引:MySQL 中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数据更快一点。

◆ 唯一索引:索引列中的值必须是唯一的,但是允许为空值,

◆ 主键索引:是一种特殊的唯一索引,不允许有空值。

组合索引:

多个字段组合上创建的索引,只有在查询条件中使用了这些字段的左边字段时,索引才会被使用,使用组合索引时遵循最左前缀集合。

全文索引:

只有在 MyISAM 引擎上才能使用,只能在 CHAR,VARCHAR,TEXT 类型字段上使用全文索引,介绍了要求,说说什么是全文索引,就是在一堆文字中,通过其中的某个关键字等,就能找到该字段所属的记录行,比如有\”你是个靓仔,靓女 …\” 通过靓仔,可能就可以找到该条记录

空间索引:

空间索引是对空间数据类型的字段建立的索引,MySQL 中的空间数据类型有四种,GEOMETRY、POINT、LINESTRING、POLYGON。在创建空间索引时,使用 SPATIAL 关键字。要求,引擎为 MyISAM,创建空间索引的列,必须将其声明为 NOT NULL。

11、什么是散列表? select * 和 select 1?

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

有时候为了提高效率,只是为了测试下某个表中是否存在记录,就用 1 来代替。

12、MySQL 的主从复制了解吗?

主库将变更写入 binlog 日志,然后从库连接到主库之后,从库有一个 IO 线程,将主库的binlog 日志拷贝到自己本地,写入一个 relay 中继日志中接着从库中有一个 SQL 线程会从中继日志读取 binlog,然后执行 binlog 日志中的内容,也就是在自己本地再次执行一遍 SQL。

13、Spring 框架事务注解用什么注解?使用该注解的失效场景?

@Transactional

◆ Transactional 注解应用在非 public 修饰的方法上@Transactional 注解属性propagation 设置错误

◆ @Transactional 注解属性 rollbackFor 设置错误

◆ 同一个类中方法调用,导致@Transactional 失效

◆ 异常被 catch“吃了”导致@Transactional 失效

14、final、finally、finallize?finally 是在 return 之前执行还是之后?finally 块里的代码一定会执行吗?

◆ final 可以用来修饰类、方法、变量,分别有不同的意义,final 修饰的 class 代表不可以继承扩展,final 的变量是不可以修改的,而 final 的方法也是不可以重写的(override)。

◆ finally 是 Java 保证重点代码一定要被执行的一种机制。可以使用 try-finally 或者 try-catch-finally 来进行类似关闭 JDBC 连接、保证 unlock 锁等动作。

◆ finalize 是基础类 java.lang.Object 的一个方法,设计目的是保证对象在被垃圾收集前完成特定资源的回收。finalize 机制现在已经不推荐使用,并且在 JDK 9 开始被标记为deprecated。

finally 块的语句在 try 或 catch 中的 return 语句执行之后返回之前执行且 finally 里的修改语句可能影响也可能不影响 try 或 catch 中 return 已经确定的返回值,若 finally 里也有 return 语句则覆盖 try 或 catch 中的 return 语句直接返回。finally 块里的代码不一定会执行。比如:

◆ try 语句没有被执行到,如在 try 语句之前就返回了,这样 finally 语句就不会执行,这也说明了 finally 语句被执行的必要而非充分条件是:相应的 try 语句一定被执行到。

◆ 在 try 块中有 System.exit(0**

15、I/O 多路复用实现方式有哪些?

◆ select

◆ poll

◆ epoll

16、select、poll、epoll 区别有哪些?

select:它仅仅知道了,有 I/O 事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),我们只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。所以 select 具有 O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长。

poll:poll 本质上和 select 没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd 对应的设备状态, 但是它没有最大连接数的限制,原因是它是基于链表来存储的.

69epoll:epoll 可以理解为 event poll,不同于忙轮询和无差别轮询,epoll 会把哪个流发生了怎样的 I/O 事件通知我们。所以我们说 epoll 实际上是事件驱动(每个事件关联上 fd)的,此时我们对这些流的操作都是有意义的。(复杂度降低到了 O(1)),通过红黑树和双链表数据结构,并结合回调机制,造就了 epoll 的高效,epoll_create(),epoll_ctl()和epoll_wait()系统调用。

17、哈希算法解决哈希冲突方式有哪些?

解决哈希冲突的方法一般有:开放寻址法、链地址法(拉链法)、再哈希法、建立公共溢出区等方法。

18、如何保证 Redis 中的数据不丢失?

单机单节点模式

使用 AOF 和 RDB 结合的方式

RDB 做镜像全量持久化,AOF 做增量持久化。因为 RDB 会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要 AOF 来配合使用。

Redis 集群模式

master 节点持久化

如果采用了主从架构,那么建议必须开启 master node 的持久化!不建议用 slave node

作为 master node 的数据热备,因为那样的话,如果你关掉 master 的持久化,可能在master 宕机重启的时候数据是空的,然后可能一经过复制,salve node 数据也丢了,master 就会将空的数据集同步到 slave 上去,所有 slave 的数据全部清空。

Redis 断点续传

从 redis 2.8 开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份。

主备切换的过程,可能会导致数据丢失

解决异步复制和脑裂导致的数据丢失

redis.conf 中

min-slaves-to-write 1

min-slaves-max-lag 10

要求至少有 1 个 slave,数据复制和同步的延迟不能超过 10 秒

如果说一旦所有的 slave,数据复制和同步的延迟都超过了 10 秒钟,那么这个时候master 就不会再接收任何请求了

上面两个配置可以减少异步复制和脑裂导致的数据丢失。

19、如何保证 Redis 中的数据都是热点数据?

◆ Redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。Redis 提供 6 种

数据淘汰策略:

◆ volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

◆ volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

◆ volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

◆ allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

◆ allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

◆ no-enviction(驱逐):禁止驱逐数据

20、Redis 持久化机制是如何做的?

RDB

RDB 持久化方式,是将 Redis 某一时刻的数据持久化到磁盘中,是一种快照式的持久化方法。

RDB 优点:

◆ RDB 是一个非常紧凑(有压缩)的文件,它保存了某个时间点的数据,非常适用于数据的备份。

◆ RDB 作为一个非常紧凑(有压缩)的文件,可以很方便传送到另一个远端数据中心 ,非常适用于灾难恢复.

◆ RDB 在保存 RDB 文件时父进程唯一需要做的就是 fork 出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他 IO 操作,所以 RDB 持久化方式可以最大化redis 的性能.

◆ 与 AOF 相比,在恢复大的数据集的时候,RDB 方式会更快一些.

RDB 缺点:

◆ Redis 意外宕机 时,会丢失部分数据

◆ 当 Redis 数据量比较大时,fork 的过程是非常耗时的,fork 子进程时是会阻塞的,在这期间 Redis 是不能响应客户端的请求的。

AOF

AOF 方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行一遍。

AOF 优点:

◆ 使用 AOF 会让你的 Redis 更加持久化。

◆ AOF 文件是一个只进行追加的日志文件,不需要在写入时读取文件。

◆ Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写 。

◆ AOF 文件可读性高,分析容易。AOF 缺点:

◆ 对于相同的数据来说,AOF 文件大小通常要大于 RDB 文件

◆ 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB

混合持久化方式

Redis 4.0 之后新增的方式,混合持久化是结合了 RDB 和 AOF 的优点,在写入的时候,先把当前的数据以 RDB 的形式写入文件的开头,再将后续的操作命令以 AOF 的格式存入文件,这样既能保证 Redis 重启时的速度,又能减低数据丢失的风险。

21、Redis 为什么在使用 RDB 进行快照时会通过子进程的方式进行实现?

◆ 通过 fork 创建的子进程能够获得和父进程完全相同的内存空间,父进程对内存的修改对于子进程是不可见的,两者不会相互影响;

◆ 通过 fork 创建子进程时不会立刻触发大量内存的拷贝,内存在被修改时会以页为单位进行拷贝,这也就避免了大量拷贝内存而带来的性能问题;

22、介绍下 MySQL 的主从复制原理?产生主从延迟的原因?

◆ 主从复制原理: 主库将变更写入 binlog 日志,然后从库连接到主库之后,从库有一个IO 线程,将主库的 binlog 日志拷贝到自己本地,写入一个 relay 中继日志中。 接着从库中有一个 SQL 线程会从中继日志读取 binlog,然后执行 binlog 日志中的内容,也就是在自己本地再次执行一遍 SQL。

◆ 主从延迟:

a. 主库的从库太多

b. 从库硬件配置比主库差

c. 慢 SQL 语句过多

d. 主从库之间的网络延迟

e. 主库读写压力大

23、父进程如果宕掉,子进程会怎样?

如果父进程是会话首进程,那么父进程退出后,子进程也会退出;反之如果父进程不是会话首进程,那么父进程退出后,子进程不会退出,而它的一个或多个子进程还在运行,那么这些子进程就成为孤儿进程。

24、孤儿进程和僵尸进程有什么区别?

孤儿进程:父进程结束了,而它的一个或多个子进程还在运行,那么这些子进程就成为孤儿进程(father died)。子进程的资源由 init 进程(进程号 PID = 1)回收。

僵尸进程:子进程退出了,但是父进程没有用 wait 或 waitpid 去获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这种进程称为僵死进程。

25、MySQL 中有哪几种锁?

◆ 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

◆ 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

◆ 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

26、互斥锁(mutex)和自旋锁(spinlock)分别在什么场景使用?

在多核机器中,如果锁住的“事务”很简单,占用很少的时间,就应该使用 spinlock,这个时候 spinlock 的代价比 mutex 会小很多。”事务”很快执行完毕,自旋的消耗远远小于陷入 sleep 和 wake 的消耗。如果锁住“事务”粒度较大,就应该使用 mutex,因为如果用spinlock,那么在“事务”执行过程中自旋很长时间还不如使得线程 sleep。

在单核机器中。spinlock 没有任何意义的,spinlock 只会浪费唯一核心的 cpu 时间片,这个时刻没有任何线程会运行的。所以单核机器中,不论锁住的”事务”的粒度大小都要使用。

27、描述 Synchronized、ReentrantLock 的区别 ?

◆ synchronized 是关键字,ReentrantLock 是 API 接口

◆ Lock 需要手动加锁,手动释放锁

◆ synchronized 不可中断,ReentrantLock 可中断、可超时

◆ synchronized 是非公平锁,ReentrantLock 公平、非公平皆可

◆ ReentrantLock 支持 Condition,多条件

28、HashMap 扩容操作是怎么实现的?

◆ 在 jdk1.8 中,resize 方法是在 hashmap 中的键值对大于阀值时或者初始化时,就调用 resize 方法进行扩容;

◆ 每次扩展的时候,都是扩展 2 倍;

◆ 扩展后 Node 对象的位置要么在原位置,要么移动到原偏移量两倍的位置。

29、ConcurrentHashMap 1.7 与 1.8 区别?

◆ 1.8 采用 synchronized 代替可重入锁 ReentrantLock (现代 JDK 中,synchronized已经被不断优化,可以不再过分担心性能差异)

◆ 1.8 取消了 Segment 分段锁的数据结构,使用数组+链表+红黑树的结构代替

◆ 1.8 对每个数组元素加锁,1.7 对要操作的 Segment 数据段加锁

30、如何使用 Java 的反射?

◆ 通过一个全限类名创建一个对象

Class.forName(“全限类名”); 例如:com.mysql.jdbc.Driver Driver 类已经被加载到 jvm中,并且完成了类的初始化工作就行了

◆ 类名.class; 获取 Class<?> clz 对象

对象.getClass();

◆ 获取构造器对象,通过构造器 new 出一个对象

Clazz.getConstructor([String.class]);

Con.newInstance([参数]);

◆ 通过 class 对象创建一个实例对象(就相当与 new 类名()无参构造器)

Cls.newInstance();

◆ 通过 class 对象获得一个属性对象

Field c=cls.getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。

Field c=cls.getDeclaredFields():获得某个类的所有声明的字段,即包括 public、private和 proteced,但是不包括父类的声明字段

◆ 通过 class 对象获得一个方法对象

Cls.getMethod(“方法名”,class……parameaType);(只能获取公共的)

Cls.getDeclareMethod(“方法名”);(获取任意修饰的方法,不能执行私有)

M.setAccessible(true);(让私有的方法可以执行)

◆ 让方法执行

Method.invoke(obj 实例对象,obj 可变参数);—–(是有返回值的)

本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com

点赞 0
收藏 0

文章为作者独立观点不代本网立场,未经允许不得转载。