代码编织梦想

1.常用的单例模式

概述:像Windows系统的任务管理器一样,你无论打开多少次,始终显示的一个窗口。如何保证一个类只有一个实例并且这个实例易于被访问呢,定义一个统一的全局变量可以确保对象随时可以被访问,但不能防止创建多个对象。一个最好的办法就是让类自身负责创建和保存它的唯一实例,并保证不创建其他实例,它还提供了一个访问该实例的方法,这就是单例模式的动机。。一点都不鸡冻-_-||。。

单例模式的定义:

  单例模式:确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。

  Singleton Pattern:Ensure  a class has only one instance, and provide a global point of access to it.

  单例模式是一种对象创建型模式。单例模式有三个要点:一是某个类只有一个实;二是它必须自行创建这个实例;三是它必须像整个系统提供这个实例。

单例模式的实现:

懒汉

  public class LazySingleton
    {
        private static LazySingleton instance = null;

        //程序运行时创建一个静态只读的辅助对象
        private static readonly object syncRoot = new object();

        private LazySingleton() { }

        public static LazySingleton GetInstance()
        {
            //第一重判断,先判断实例是否存在,不存在再加锁处理
            if(instance == null)
            {
                //加锁的程序在某一时刻只允许一个线程访问
                lock (syncRoot)
                {
                    //第二重判断
                    if(instance == null)
                    {
                        instance = new LazySingleton();//创建单例实例
                    }
                }
            }
            return instance;
        }
    }

饿汉

    public class EagerSingleton
    {
        private static EagerSingleton instance = new EagerSingleton();
        private EagerSingleton() { }    
        public static EagerSingleton GetInstance()
        {
            return instance;
        }
    }

2.Java常用的结构有哪些

数组  栈 队列 链表 树  堆  图 散列表

3.Spring AOP是什么意思,通俗讲解

     切面编程,就是在你项目原有的功能基础上,通过AOP去添加新的功能,这些功能是建立在原有功能的基础上的,而且原有的功能并不知道你已经添加了新的功能。比如说,你去ATM取钱,取钱是一个功能,取完钱后向你的手机发送一条取钱信息,这就是新加的功能。
    AOP就是在某一个类或方法执行前后打个标记,声明在执行到这里之前要先执行什么,执行完这里之后要接着执行什么。插入了新的执行方法。

    当我们需要在许多类中添加相同逻辑(或记录等其他)代码的时候,一般我们编程会在每一个类中都写上这些代码。当需要修改的时候,我们又必须找出这些类来删除这些逻辑代码。这里,你觉不觉得有什么问题。这好像关系到复用的问题,那么可以用聚合或继承来完成?那么再继续下去,我们需要这些逻辑代码指定到类中的某个方法前面执行,或者在方法后面执行,又或者我想指定在类的某一个位置去执行它,那么这就不是复用的问题了,而是要修改类了,变成动态的了。那么就出现了aop这个概念-面向切面编程。


4.JDK,JRE,JVM三者关系

  JDK(Java Development Kit)是针对Java开发员的产品,是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。Java Runtime Environment(JRE)是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。JVM是Java Virtual Machine(Java虚拟机)的缩写,是整个java实现跨平台的最核心的部分,能够运行以Java语言写作的软件程序。JDK 包含JRE,JRE包含JVM。

5.一般什么原因会造成死锁,怎么解决?

操作系统中有若干进程并发执行,它们不断申请、使用、释放系统资源,虽然系统的进  
程协调、通信机构会对它们进行控制,但也可能出现若干进程都相互等待对方释放资源才能  
继续运行,否则就阻塞的情况。此时,若不借助外界因素,谁也不能释放资源,谁也不能解  
除阻塞状态。根据这样的情况,操作系统中的死锁被定义为系统中两个或者多个进程无限期  
地等待永远不会发生的条件,系统处于停滞状态,这就是死锁。  
产生死锁的原因主要是:  
(1) 因为系统资源不足。  
(2) 进程运行推进的顺序不合适。  
(3) 资源分配不当等。  
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则  
就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。  
产生死锁的四个必要条件:  
(1) 互斥条件:一个资源每次只能被一个进程使用。  
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。  
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。  
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。  
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之  
一不满足,就不会发生死锁。  
死锁的解除与预防:  
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和  
解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确  
定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态  
的情况下占用资源。因此,对资源的分配要给予合理的规划。

6.HashMap,LinkedHashMap,TreeMap区别

Map 主要用于存储键(key)值(value)对,根据键得到值,因此键不允许键重复,但允许值重复。

HashMap 
是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力。                                                                   
LinkedHashMapLinkedHashMap也是一个HashMap,但是内部维持了一个双向链表,可以保持顺序

TreeMap 可以用于排序

linkedMap在于存储数据你想保持进入的顺序与被取出的顺序一致的话,优先考虑LinkedMap,hashMap键只能允许为一条为空,value可以允许为多条为空,键唯一,但值可以多个。

经本人测试linkedMap键和值都不可以为空

7.多线程两种实现方法

多线程有两种实现方法,分别是继承Thread类与实现Runnable接口

同步的实现方法有两种,分别是synchronized,wait与notify

先看一下java线程运行时各个阶段的运行状态

java实现多线程有两种方法

1、继承Thread类

2、实现Runnable接口

这两种方法的共同点:

不论用哪种方法,都必须用Thread(如果是Thead子类就用它本身)产生线程,然后再调用start()方法。

两种方法的不同点:

1、继承Thread类有一个缺点就是单继承,而实现Runnable接口则弥补了它的缺点,可以实现多继承

2、继承Thread类必须如果产生Runnable实例对象,就必须产生多个Runnable实例对象,然后再用Thread产生多个线程;而实现Runnable接口,只需要建立一个实现这个类的实例,然后用这一个实例对象产生多个线程。即实现了资源的共享性

基于以上两点所以建议用第二种方法

8.什么是消息队列?

一、什么是消息队列?

消息队列不知道大家看到这个词的时候,会不会觉得它是一个比较高端的技术,反正我是觉得它好像是挺牛逼的。

消息队列,一般我们会简称它为MQ(Message Queue),嗯,就是很直白的简写。

我们先不管消息(Message)这个词,来看看队列(Queue)。这一看,队列大家应该都熟悉吧。

队列是一种先进先出的数据结构。

消息队列可以简单理解为:把要传输的数据放在队列中。

9.为什么站点使用https加密之后还能看到相关数据

这是因为:https(ssl)加密是发生在应用层与传输层之间,所以在传输层看到的数据才是经过加密的,而我们捕捉到的http post,是应用层的数据,此时还没有经过加密。这些明文信息,其实就是你的本地数据。

加密数据只有客户端和服务器端才能得到明文,客户端到服务端的通信过程是安全的。

可能有些读者会对此表示担忧了:这样的话密码不是会被本地恶意软件截获么?只能说的确存在这样的可能。不过在银行电商等安全防护程度较高的网站,除了https加密外,还有安全控件加密,用户必须下载安全控件后才能输入密码,以支付宝为例:通过下图可以发现就算在本地也无法查看账号信息。

针对这个问题,Gworg CA建议:行政、金融、电商等需要高安全防护的站点在实行https加密外,还应该部署Gworg客户端证书,以强身份认证的方式替代不安全的账号密码认证,确保登录过程中的安全无忧,同时还能弱口令漏洞,最大程度保护用户信息安全。

此外,针对使用安全控件辅助登录的站点,Gworg还建议使用代码签名证书,以保证安全控件在下载传输过程中没有被篡改及破坏。从而保证代码的完整性,保护用户不会被病毒、恶意代码和间谍软件所侵害,真正做到全面安全防护。

10.JAVA中,启动线程的三种方法

1、继承Thread类, 重写run方法,在main函数中,调用start方法。代码如下:

//播放音乐线程类  

class MusicThread extends Thread {  

    public void run() {  

        for (int i = 0; i < 50; i++) {  

            System.out.println("播放音乐" + i);  

        }  

    }  

}  

//主线程类  

public class ThreadDemo3 {  

    public static void main(String[] args) {  

        //启动播放音乐的线程  

        MusicThread thread1 = new MusicThread();  

        thread1.start();  

        //主线程  

        for (int i = 0; i < 50; i++) {  

            System.out.println("打游戏" + i);  

        }  

    }  

}  

2、实现Runnable接口,重写run方法,在main函数中,调用start方法。代码如下:

//1):定义一个类A实现于java.lang.Runnable接口,注意A类不是线程类.  

class MusicImplements implements Runnable{  

    //2):在A类中覆盖Runnable接口中的run方法.  

    public void run() {  

        //3):在run方法中编写需要执行的操作  

        for(int i = 0; i < 50; i ++){  

            System.out.println("播放音乐"+i);  

        }  

          

    }  

}  

  

public class ImplementsRunnableDemo {  

    public static void main(String[] args) {  

        for(int j = 0; j < 50; j ++){  

            System.out.println("运行游戏"+j);  

            if(j == 10){  

                //4):在main方法(线程)中,创建线程对象,并启动线程  

                MusicImplements mi = new MusicImplements();  

                Thread t = new Thread(mi);  

                t.start();  

            }  

        }  

    } 

}  

3、实现Callable接口,重写call()方法,在main函数中调用start()方法。

import java.util.concurrent.Callable;

public class ThreadImplementsCallable implements Callable<Integer> {

  private int i; 

  @Override

  public Integer call() throws Exception {

    for(; i < 100; i++){

      System.out.println(Thread.currentThread().getName() + " " + i);

    }

    return i;

  }

}

import java.util.concurrent.Callable;

import java.util.concurrent.FutureTask;

public class Main {

  public static void main(String[] args) {

    Callable<Integer> callable = new ThreadImplementsCallable();

    FutureTask<Integer> futureTask = new FutureTask<>(callable);

    for(i = 0; i < 100; i++){

      System.out.println(Thread.currentThread().getName() + " " + i);

      if (i == 5) {

        new Thread(futureTask).start();

        new Thread(futureTask).start();

      }

    }

    try {

      System.out.println("futureTask ruturn: " + futureTask.get());

    } catch (Exception e) {

      e.printStackTrace();

    }

  }

}

11.乐观锁与悲观锁原理及实现

一、乐观锁
 总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制或CAS操作实现。

 version方式:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。

核心SQL代码:

update table set x=x+1, version=version+1 where id=#{id} and version=#{version};  

 CAS操作方式:即compare and swap 或者 compare and set,涉及到三个操作数,数据所在的内存值,预期值,新值。当需要更新时,判断当前内存值与之前取到的值是否相等,若相等,则用新值更新,若失败则重试,一般情况下是一个自旋操作,即不断的重试。

二、悲观锁
 总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加锁(读锁、写锁、行锁等),当其他线程想要访问数据时,都需要阻塞挂起。可以依靠数据库实现,如行锁、读锁和写锁等,都是在操作之前加锁,在Java中,synchronized的思想也是悲观锁。


12.xss攻击,csrf攻击,SQL注入

1、xss攻击,跨站脚本攻击值得是攻击者在网页中嵌入恶意脚本程序,当用户打开浏览器,脚本程序便开始在客户端的浏览器上执行,一盗取客户端cookie等信息,利用系统对用户的信任。

防御措施:将html转移处理htmlspe

2、csrf攻击是跨站请求伪造,攻击者盗用了你的身份,以你的名义向第三方网站发送恶意请求,利用系统对页面浏览器的信任。

防御措施:①将cookie设置为HttpOnly。如果cookie中设置了HttpOnly属性,那么通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击,窃取cookie内容,这样就增加了cookie的安全性。

//设置cookie

response.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly")

②设置token

③通过refer识别:根据http协议,在http投中有一个字符安叫refer,它记录了该http请求的来源地址

3、SQL注入,通过预处理可以解决

13.如何避免内存泄漏、溢出的几种常用方法

尽早释放无用对象的引用。

好的办法是使用临时变量的时候,让引用变量在退出活动域后自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄露。

程序进行字符串处理时,尽量避免使用String,而应使用StringBuffer。

因为每一个String对象都会独立占用内存一块区域

尽量少用静态变量。

因为静态变量是全局的,GC不会回收。

避免集中创建对象尤其是大对象,如果可以的话尽量使用流操作。

JVM会突然需要大量内存,这时会触发GC优化系统内存环境;

尽量运用对象池技术以提高系统性能。

生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。

不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。

可以适当的使用hashtable,vector 创建一组对象容器,然后从容器中去取那些对象,而不用每次new之后又丢弃。

优化配置。

  • 设置-Xms、-Xmx相等;
  • 设置NewSize、MaxNewSize相等;
  • 设置Heap size, PermGen space;

14.哪些情况下索引会失效?

对查询进行优化,尽量避免全表扫描,避免导致索引失效

  • 在where子句中进行null值判断的话会导致引擎放弃索引而产生全表扫描
SELECT id FROM table WHERE num is null

在建立数据库的时候因尽量为字段设置默认值,如int类型可以使用0,varchar类型使用 ''
当你在指定类型大小如int(11)时,其实空间就已经固定了,即时存的是null也是这个大小
  • 避免在where子句中使用!= ,< >这样的符号,否则会导致引擎放弃索引而产生全表扫描
SELECT id FROM table WHERE num != 0
  • 避免在where子句中使用or来连接条件,因为如果俩个字段中有一个没有索引的话,引擎会放弃索引而产生全表扫描
SELECT id FROM table WHERE num = 0 OR num = 1
  • 可以考虑使用between,但是只能是连续的数值
SELECT id FROM table WHERE num BETWEEN 0 AND 1
  • 避免在where子句中使用int关于网上说的MySQL在使用int不走索引的问题,严谨的来说的话分为俩种情况
    • 走索引的
SELECT id FROM table WHERE num IN (1)
    • 不走索引的
SELECT id FROM table WHERE num IN (1,2)
其实在in里面,如果只有一个值的话是等价于num = 1的
  • 避免在where子句中=的左边使用表达式操作或者函数操作
    • 表达式
SELECT id FROM table WHERE num / 2 = 1
    • 函数操作
SELECT id FROM table WHERE SUBSTRING(name,1,2) = 'wise'
  • 避免在where子句中使用like模糊查询
SELECT id FROM table WHERE name LIKE 'wise'
  • 在使用联合索引是要注意最左原则,例如如果当前联合索引是index(a,b,c),那么如果where子句中有a就会用到联合索引,但是如果只用到b,c就会失去索引效果
SELECT id FROM table WHERE name LIKE 'wise'

15.数据库分区、分表、分库、分片 

一、分区的概念

        数据分区是一种物理数据库的设计技术,它的目的是为了在特定的SQL操作中减少数据读写的总量以缩减响应时间。

        分区并不是生成新的数据表,而是将表的数据均衡分摊到不同的硬盘,系统或是不同服务器存储介子中,实际上还是一张表。另外,分区可以做到将表的数据均衡到不同的地方,提高数据检索的效率,降低数据库的频繁IO压力值,分区的优点如下:

1、相对于单个文件系统或是硬盘,分区可以存储更多的数据;

2、数据管理比较方便,比如要清理或废弃某年的数据,就可以直接删除该日期的分区数据即可;

3、精准定位分区查询数据,不需要全表扫描查询,大大提高数据检索效率;

4、可跨多个分区磁盘查询,来提高查询的吞吐量;

5、在涉及聚合函数查询时,可以很容易进行数据的合并;

二、分类 (row 行 ,column 列)

1、水平分区

这种形式分区是对表的行进行分区,通过这样的方式不同分组里面的物理列分割的数据集得以组合,从而进行个体分割(单分区)或集体分割(1个或多个分区)。所有在表中定义的列在每个数据集中都能找到,所以表的特性依然得以保持。

举个简单例子:一个包含十年发票记录的表可以被分区为十个不同的分区,每个分区包含的是其中一年的记录。(朋奕注:这里具体使用的分区方式我们后面再说,可以先说一点,一定要通过某个属性列来分割,譬如这里使用的列就是年份)

2、垂直分区

这种分区方式一般来说是通过对表的垂直划分来减少目标表的宽度,使某些特定的列被划分到特定的分区,每个分区都包含了其中的列所对应的行。

举个简单例子:一个包含了大text 和B L OB 列的表,这些text和BLOB列又不经常被访问,这时候就要把这些不经常使用的text和BLOB了划分到另一个分区,在保证它们数据相关性的同时还能提高访问速度。

在数据库供应商开始在他们的数据库引擎中建立分区(主要是水平分区)时,DBA和建模者必须设计好表的物理分区结构,不要保存冗余的数据(不同表中同时都包含父表中的数据)或相互联结成一个逻辑父对象(通常是视图)。这种做法会使水平分区的大部分功能失效,有时候也会对垂直分区产生影响。

三、分区、分表、分库的详细理解

一、什么是分区、分表、分库

分区

就是把一张表的数据分成N个区块,在逻辑上看最终只是一张表,但底层是由N个物理区块组成的

分表

就是把一张表按一定的规则分解成N个具有独立存储空间的实体表。系统读写时需要根据定义好的规则得到对应的字表明,然后操作它。

分库

一旦分表,一个库中的表会越来越多

将整个数据库比作图书馆,一张表就是一本书。当要在一本书中查找某项内容时,如果不分章节,查找的效率将会下降。而同理,在数据库中就是分区。

二、常用的单机数据库的瓶颈

问题描述

  • 单个表数据量越大,读写锁,插入操作重新建立索引效率越低。

  • 单个库数据量太大(一个数据库数据量到1T-2T就是极限)

  • 单个数据库服务器压力过大

  • 读写速度遇到瓶颈(并发量几百)

三、分区

什么时候考虑使用分区?

  • 一张表的查询速度已经慢到影响使用的时候。

  • sql经过优化

  • 数据量大

  • 表中的数据是分段的

  • 对数据的操作往往只涉及一部分数据,而不是所有的数据

分区解决的问题

主要可以提升查询效率

分区的实现方式(简单)

mysql5 开始支持分区功能

  1. CREATE TABLE sales (

  2. id INT AUTO_INCREMENT,

  3. amount DOUBLE NOT NULL,

  4. order_day DATETIME NOT NULL,

  5. PRIMARY KEY(id, order_day)

  6. ) ENGINE=Innodb

  7. PARTITION BY RANGE(YEAR(order_day)) (

  8. PARTITION p_2010 VALUES LESS THAN (2010),

  9. PARTITION p_2011 VALUES LESS THAN (2011),

  10. PARTITION p_2012 VALUES LESS THAN (2012),

  11. PARTITION p_catchall VALUES LESS THAN MAXVALUE);

四、分表

什么时候考虑分表?

  • 一张表的查询速度已经慢到影响使用的时候。

  • sql经过优化

  • 数据量大

  • 当频繁插入或者联合查询时,速度变慢

分表解决的问题

分表后,单表的并发能力提高了,磁盘I/O性能也提高了,写操作效率提高了

  • 查询一次的时间短了

  • 数据分布在不同的文件,磁盘I/O性能提高

  • 读写锁影响的数据量变小

  • 插入数据库需要重新建立索引的数据减少

分表的实现方式(复杂)

需要业务系统配合迁移升级,工作量较大

分区和分表的区别与联系

  • 分区和分表的目的都是减少数据库的负担,提高表的增删改查效率。

  • 分区只是一张表中的数据的存储位置发生改变,分表是将一张表分成多张表。

  • 当访问量大,且表数据比较大时,两种方式可以互相配合使用。

  • 当访问量不大,但表数据比较多时,可以只进行分区。

常见分区分表的规则策略(类似)

  1. Range(范围)

  2. Hash(哈希)

  3. 按照时间拆分

  4. Hash之后按照分表个数取模

  5. 在认证库中保存数据库配置,就是建立一个DB,这个DB单独保存user_id到DB的映射关系

12306的订单是如何存储的?

五、分库

什么时候考虑使用分库?

  • 单台DB的存储空间不够

  • 随着查询量的增加单台数据库服务器已经没办法支撑

分库解决的问题

其主要目的是为突破单节点数据库服务器的 I/O 能力限制,解决数据库扩展性问题。 

垂直拆分

将系统中不存在关联关系或者需要join的表可以放在不同的数据库不同的服务器中。

按照业务垂直划分。比如:可以按照业务分为资金、会员、订单三个数据库。

需要解决的问题:跨数据库的事务、jion查询等问题。

水平拆分

例如,大部分的站点。数据都是和用户有关,那么可以根据用户,将数据按照用户水平拆分。

按照规则划分,一般水平分库是在垂直分库之后的。比如每天处理的订单数量是海量的,可以按照一定的规则水平划分。需要解决的问题:数据路由、组装。

读写分离

对于时效性不高的数据,可以通过读写分离缓解数据库压力。需要解决的问题:在业务上区分哪些业务上是允许一定时间延迟的,以及数据同步问题。

思路

垂直分库-->水平分库-->读写分离

六、拆分之后面临新的问题

问题

  • 事务的支持,分库分表,就变成了分布式事务

  • join时跨库,跨表的问题

  • 分库分表,读写分离使用了分布式,分布式为了保证强一致性,必然带来延迟,导致性能降低,系统的复杂度变高。

常用的解决方案:

对于不同的方式之间没有严格的界限,特点不同,侧重点不同。需要根据实际情况,结合每种方式的特点来进行处理。

选用第三方的数据库中间件(Atlas,Mycat,TDDL,DRDS),同时业务系统需要配合数据存储的升级。

七、数据存储的演进

单库单表

单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到。

单库多表

随着用户数量的增加,user表的数据量会越来越大,当数据量达到一定程度的时候对user表的查询会渐渐的变慢,从而影响整个DB的性能。如果使用mysql, 还有一个更严重的问题是,当需要添加一列的时候,mysql会锁表,期间所有的读写操作只能等待。

可以通过某种方式将user进行水平的切分,产生两个表结构完全一样的user_0000,user_0001等表,user_0000 + user_0001 + …的数据刚好是一份完整的数据。

多库多表

随着数据量增加也许单台DB的存储空间不够,随着查询量的增加单台数据库服务器已经没办法支撑。这个时候可以再对数据库进行水平拆分。

八、总结

总的来说,优先考虑分区。当分区不能满足需求时,开始考虑分表,合理的分表对效率的提升会优于分区。

16. Dubbo和SpringCloud的对比

来源(背景):
Dubbo,是阿里巴巴服务化治理的核心框架,并被广泛应用于阿里巴巴集团的各成员站点。
Spring Cloud,从命名我们就可以知道,它是Spring Source的产物,Spring社区的强大背书可以说是Java企业界最有影响力的组织了,除了Spring Source之外,还有Pivotal和Netfix是其强大的后盾与技术输出。其中Netflix开源的整套微服务架构套件是Spring Cloud的核心。
 
传输:
Dubbo由于是二进制的传输,占用带宽会更少;
Spring Cloud是http协议传输,带宽会比较多,同时使用http协议一般会使用JSON报文,消耗会更大。但是在国内95%的公司内,网络消耗不是什么太大问题,如果真的成了问题,通过压缩、二进制、高速缓存、分段降级等方法,很容易解。
 
开发难度:
Dubbo的开发难度较大,原因是dubbo的jar包依赖问题很多大型工程无法解决;
Spring Cloud的接口协议约定比较自由且松散,需要有强有力的行政措施来限制接口无序升级
 
后续改进:
Dubbo通过dubbofilter,很多东西没有,需要自己继承,如监控,如日志,如限流,如追踪
Spring Cloud自己带了很多监控、限流措施,但是功能可能和欧美习惯相同,国内需要进行适当改造,但更简单,就是ServletFilter而已,但是总归比dubbo多一些东西是好的;
 
注册中心:
Dubbo的注册中心可以选择zk,redis等多种;
Spring Cloud:的注册中心只能用eureka或者自研;
配置中心:
dubbo:如果我们使用配置中心、分布式跟踪这些内容都需要自己去集成,无形中增加了使用难度。
Spring Cloud:提供了微服务的一整套解决方案:服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等
核心部件的比较:
Dubbo:
Provider:暴露服务的提供方,可以通过 jar 或者容器的方式启动服务。
Consumer:调用远程服务的服务消费方。
Registry:服务注册中心和发现中心。
Monitor:统计服务和调用次数,调用时间监控中心。(Dubbo 的控制台页面中可以显示,目前只有一个简单版本。)
Container:服务运行的容器。
Spring Cloud:
Service Provider: 暴露服务的提供方。
Service Consumer:调用远程服务的服务消费方。
EureKa Server: 服务注册中心和服务发现中心。
架构的完整度:
Dubbo只是实现了服务治理;
Spring Cloud下面有17个子项目(可能还会新增)分别覆盖了微服务架构下的方方面面,服务治理只是其中的一个方面;
一定程度来说,Dubbo只是Spring Cloud Netflix中的一个子集。
服务依赖方式:
Dubbo:服务提供方与消费方通过接口的方式依赖,服务调用设计如下:
Interface 层:服务接口层,定义了服务对外提供的所有接口。
Molel 层:服务的 DTO 对象层。
Business层:业务实现层,实现 Interface 接口并且和 DB 交互。
因此需要为每个微服务定义各自的 Interface 接口,并通过持续集成发布到私有仓库中。调用方应用对微服务提供的抽象接口存在强依赖关系,开发、测试、集成环境都需要严格的管理版本依赖。
通过 maven 的 install & deploy 命令把 Interface 和 Model 层发布到仓库中,服务调用方只需要依赖 Interface 和 Model 层即可。在开发调试阶段只发布 Snapshot 版本,等到服务调试完成再发布;Release 版本,通过版本号来区分每次迭代的版本。通过 xml 配置方式即可接入 Dubbo,对程序无入侵。
总之:服务提供方与消费方通过接口的方式依赖,Dubbo 服务依赖略重,需要有完善的版本管理机制,但是程序入侵少。
Spring Cloud:
服务提供方和服务消费方通过 Json 方式交互,因此只需要定义好相关 Json 字段即可,消费方和提供方无接口依赖。通过注解方式来实现服务配置,对于程序有一定入侵。
通过 Json 交互,省略了版本管理的问题,但是具体字段含义需要统一管理,自身 Rest API 方式交互,为跨平台调用奠定了基础。
总体:
Dubbo:使用Dubbo构建的微服务架构就像组装电脑,各环节我们的选择自由度很高,但是最终结果很有可能因为一条内存质量不行就点不亮了,总是让人不怎么放心,但是如果你是一名高手,那这些都不是问题;
Spring Cloud就像品牌机,在Spring Source的整合下,做了大量的兼容性测试,保证了机器拥有更高的稳定性,但是如果要在使用非原装组件外的东西,就需要对其基础有足够的了解。
 
优缺点(综上得到):
Dubbo
优点:
1.支持各种通信协议,而且消费方和服务方使用长链接方式交互,通信速度上略胜 ;
2.采用rpc方式,性能上比Spring Cloud的rpc更好;
3.dubbo的网络消耗小于springcloud
缺点:
1.如果我们使用配置中心、分布式跟踪这些内容都需要自己去集成;
2.开发难度较大,原因是dubbo的jar包依赖问题很多大型工程无法解决;
Spring Cloud:
优点:
1、产出于Spring大家族,Spring在企业级开发框架中来头很大,可以保证后续的更新、完善。
2、spring cloud社区活跃,教程丰富,遇到问题很容易找到解决方案;
3、spring cloud功能比dubbo更加完善;
5、spring cloud采用rest访问方式,rest的技术无关性使用效果更棒;
6、spring cloud轻轻松松几行代码就完成了熔断、均衡负责、服务中心的各种平台功能;
7、从公司招聘工程师方面,spring cloud更有优势,因为其技术更新更炫;
8、提供了微服务的一整套解决方案:服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等;作为一个微服务治理的大家伙,考虑的很全面,几乎服务治理的方方面面都考虑到了,方便开发开箱即用;
缺点:
1.如果对于系统的响应时间有严格要求,长链接更合适。
2.接口协议约定比较自由且松散,需要有强有力的行政措施来限制接口无序升级

17.dubbo 熔断,限流,降级 

1.1 名词解释

consumer表示服务调用方 

provider标示服务提供方,dubbo里面一般就这么讲。

下面的A调用B服务,一般是泛指调用B服务里面的一个接口。

2.1 超时(timeout)

在接口调用过程中,consumer调用provider的时候,provider在响应的时候,有可能会慢,如果provider 10s响应,那么consumer也会至少10s才响应。如果这种情况频度很高,那么就会整体降低consumer端服务的性能。

这种响应时间慢的症状,就会像一层一层波浪一样,从底层系统一直涌到最上层,造成整个链路的超时。

所以,consumer不可能无限制地等待provider接口的返回,会设置一个时间阈值,如果超过了这个时间阈值,就不继续等待。

这个超时时间选取,一般看provider正常响应时间是多少,再追加一个buffer即可。

2.2 重试(retry)

超时时间的配置是为了保护服务,避免consumer服务因为provider 响应慢而也变得响应很慢,这样consumer可以尽量保持原有的性能。

但是也有可能provider只是偶尔抖动,那么超时后直接放弃,不做后续处理,就会导致当前请求错误,也会带来业务方面的损失。

那么,对于这种偶尔抖动,可以在超时后重试一下,重试如果正常返回了,那么这次请求就被挽救了,能够正常给前端返回数据,只不过比原来响应慢一点。

重试时的一些细化策略:

重试可以考虑切换一台机器来进行调用,因为原来机器可能由于临时负载高而性能下降,重试会更加剧其性能问题,而换一台机器,得到更快返回的概率也更大一些。

2.2.1 幂等(idempotent)

如果允许consumer重试,那么provider就要能够做到幂等。

即,同一个请求被consumer多次调用,对provider产生的影响(这里的影响一般是指某些写入相关的操作) 是一致的。

而且这个幂等应该是服务级别的,而不是某台机器层面的,重试调用任何一台机器,都应该做到幂等。

2.3 熔断(circuit break)

重试是为了应付偶尔抖动的情况,以求更多地挽回损失。

可是如果provider持续的响应时间超长呢?

如果provider是核心路径的服务,down掉基本就没法提供服务了,那我们也没话说。 如果是一个不那么重要的服务,却因为这个服务一直响应时间长导致consumer里面的核心服务也拖慢,那么就得不偿失了。

单纯超时也解决不了这种情况了,因为一般超时时间,都比平均响应时间长一些,现在所有的打到provider的请求都超时了,那么consumer请求provider的平均响应时间就等于超时时间了,负载也被拖下来了。

而重试则会加重这种问题,使consumer的可用性变得更差。

因此就出现了熔断的逻辑,也就是,如果检查出来频繁超时,就把consumer调用provider的请求,直接短路掉,不实际调用,而是直接返回一个mock的值。

等provider服务恢复稳定之后,重新调用。

2.3.1 简单的熔断处理逻辑

目前我们框架有通过注解使用的熔断器,大家可以参考应用在项目中。

2.4 限流(current limiting)

上面几个策略都是consumer针对provider出现各种情况而设计的。

而provider有时候也要防范来自consumer的流量突变问题。

这样一个场景,provider是一个核心服务,给N个consumer提供服务,突然某个consumer抽风,流量飙升,占用了provider大部分机器时间,导致其他可能更重要的consumer不能被正常服务。

所以,provider端,需要根据consumer的重要程度,以及平时的QPS大小,来给每个consumer设置一个流量上线,同一时间内只会给A consumer提供N个线程支持,超过限制则等待或者直接拒绝。

2.4.1 资源隔离

provider可以对consumer来的流量进行限流,防止provider被拖垮。 

同样,consumer 也需要对调用provider的线程资源进行隔离。 这样可以确保调用某个provider逻辑不会耗光整个consumer的线程池资源。

2.4.2 服务降级

降级服务既可以代码自动判断,也可以人工根据突发情况切换。

2.4.2.1 consumer 端

consumer 如果发现某个provider出现异常情况,比如,经常超时(可能是熔断引起的降级),数据错误,这是,consumer可以采取一定的策略,降级provider的逻辑,基本的有直接返回固定的数据。

2.4.2.2 provider 端

当provider 发现流量激增的时候,为了保护自身的稳定性,也可能考虑降级服务。 

比如,1,直接给consumer返回固定数据,2,需要实时写入数据库的,先缓存到队列里,异步写入数据库。

3 从宏观角度重新思考

宏观包括比A -> B 更复杂的长链路。

长链路就是 A -> B -> C -> D这样的调用环境。

而且一个服务也会多机部署,A 服务实际会存在 A1,A2,A3 …

微观合理的问题,宏观未必合理。

下面的一些讨论,主要想表达的观点是:如果系统复杂了,系统的容错配置要整体来看,整体把控,才能做到更有意义。

3.1 超时

如果A给B设置的超时时间,比B给C设置的超时时间短,那么肯定不合理把,A超时时间到了直接挂断,B对C支持太长超时时间没意义。

R表示服务consumer自身内部逻辑执行时间,TAB表示consumer A开始调用provider B到返回的时间 。

那么那么TAB > RB + TBC 才对。

3.2 重试

重试跟超时面临的问题差不多。

B服务一般100ms返回,所以A就给B设置了110ms的超时,而B设置了对C的一次重试,最终120ms正确返回了,但是A的超时时间比较紧,所以B对C的重试被白白浪费了。

A也可能对B进行重试,但是由于上一条我们讲到的,可能C确实性能不好,每次B重试一下就OK,但是A两次重试其实都无法正确的拿到结果。

N标示设置的重试次数

修正一下上面section的公式,TAB > RB+TBC * N。

虽然这个公式本身没什么问题,但是,如果站在长链路的视角来思考,我们需要整体规划每个服务的超时时间和重试次数,而不是仅仅公式成立即可。

比如下面情况:

A -> B -> C。

RB = 100ms,TBC=10ms

B是个核心服务,B的计算成本特别大,那么A就应该尽量给B长一点的超时时间,而尽量不要重试调用B,而B如果发现C超时了,B可以多调用几次C,因为重试C成本小,而重试B成本则很高。 so …

3.3 熔断

A -> B -> C,如果C出现问题了,那么B熔断了,则A就不用熔断了。

3.4 限流

B只允许A以QPS<=5的流量请求,而C却只允许B以QPS<=3的qps请求,那么B给A的设定就有点大,上游的设置依赖下游。

而且限流对QPS的配置,可能会随着服务加减机器而变化,最好是能在集群层面配置,自动根据集群大小调整。

3.5 服务降级

服务降级这个问题,如果从整体来操作,

1,一定是先降级优先级地的接口,两权相害取其轻 

2,如果服务链路整体没有性能特别差的点,比如就是外部流量突然激增,那么就从外到内开始降级。 

3如果某个服务能检测到自身负载上升,那么可以从这个服务自身做降级。

3.6 涟漪

A -> B -> C,如果C服务出现抖动,而B没有处理好这个抖动,造成B服务也出现了抖动,A调用B的时候,也会出现服务抖动的情况。

这个暂时的不可用状态就想波浪一样从底层传递到了上层。

所以,从整个体系的角度来看,每个服务一定要尽量控制住自己下游服务的抖动,不要让整个体系跟着某个服务抖动。

3.7 级联失败(cascading failure)

系统中有某个服务出现故障,不可用,传递性地导致整个系统服务不可用的问题。

跟上面涟漪(自造词)的区别也就是严重性的问题。

涟漪描述服务偶发的不稳定层层传递,而级联失败基本是导致系统不可用。 一般,前者可能会因为短时间内恢复而未引起重视,而后者一般会被高度重视。

3.8 关键路径

关键路径就是,你的服务想正常工作,必须要完整依赖的下游服务链,比如数据库一般就是关键路径里面的一个节点。

尽量减少关键路径依赖的数量,是提高服务稳定性的一个措施。

数据库一般在服务体系的最底层,如果你的服务可以会自己完整缓存使用的数据,解除数据库依赖,那么数据库挂掉,你的服务就暂时是安全的。

3.9 最长路径

想要优化你的服务的响应时间,需要看服务调用逻辑里面的最长路径,只有缩短最长时间路径的用时,才能提高你的服务的性能。

18.Redis 的过期策略都有哪些?

常见的有两个问题:
• 往 redis 写入的数据怎么没了?
可能有同学会遇到,在生产环境的 redis 经常会丢掉一些数据,写进去了,过一会儿可能就没了。我的天,同学,你问这个问题就说明 redis 你就没用对啊。redis 是缓存,你给当存储了是吧?
啥叫缓存?用内存当缓存。内存是无限的吗,内存是很宝贵而且是有限的,磁盘是廉价而且是大量的。可能一台机器就几十个 G 的内存,但是可以有几个 T 的硬盘空间**。redis 主要是基于内存来进行高性能、高并发的读写操作的**。
那既然内存是有限的,比如 redis 就只能用 10G,你要是往里面写了 20G 的数据,会咋办?当然会干掉 10G 的数据,然后就保留 10G 的数据了。那干掉哪些数据?保留哪些数据?当然是干掉不常用的数据,保留常用的数据了。

• 数据明明过期了,怎么还占用着内存?
这是由 redis 的过期策略来决定。

面试题剖析
redis 过期策略
redis 过期策略是:定期删除+惰性删除。
所谓定期删除,指的是 redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 key,检查其是否过期,如果过期就删除。
假设 redis 里放了 10w 个 key,都设置了过期时间,你每隔几百毫秒,就检查 10w 个 key,那 redis 基本上就死了,cpu 负载会很高的,消耗在你的检查过期 key 上了。注意,这里可不是每隔 100ms 就遍历所有的设置过期时间的 key,那样就是一场性能上的灾难。实际上 redis 是每隔 100ms 随机抽取一些 key 来检查和删除的。

但是问题是,定期删除可能会导致很多过期 key 到了时间并没有被删除掉,那咋整呢?所以就是惰性删除了。这就是说,在你获取某个 key 的时候,redis 会检查一下 ,这个 key 如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。
获取 key 的时候,如果此时 key 已经过期,就删除,不会返回任何东西。
但是实际上这还是有问题的,如果定期删除漏掉了很多过期 key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期 key 堆积在内存里,导致 redis 内存块耗尽了,咋整?
答案是:走内存淘汰机制。

内存淘汰机制
redis 内存淘汰机制有以下几个:
• noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了。
• allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)。
• allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的 key 给干掉啊。
• volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 key(这个一般不太合适)。
• volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 key。
• volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 key 优先移除。

19、java中容器有哪些?

1、什么是容器?

容器就是用来存放和管理对象的对象。

2、java中容器有哪些?

(1)数组
数组是一种典型的容器,但是数组j的容量是有限制的。
(2)java.Util下的集合容器

五大接口:
Collection接口:List、Set、Queue接口。
Map接口。
Iterator迭代器。
每个接口下面有其多个实现类。具体容器见以下链接。
List接口:java容器——List接口(代码模拟ArrayList和LinkedList类的底层实现)
Set接口:java学习:java容器——Set接口分析
Queue接口:java学习:java容器——Queue接口分析及应用
Map接口:java学习:java容器——Map接口(代码模拟HashMap的底层实现)
Iterator迭代器:java学习:java容器——Iterator迭代器详细分析


20.springBoot事务

Transactional注解

21.spring三种注入方式

构造器注入,setter注入,接口注入

22.array和arrayList有什么区别

①Array是Java中的数组,声明数组有三种方式
int[] a=new int[10];
int a[]=new int[10];
int a[]={1,2,3,4};
可以看出:在定义一个数组的时候,必须指定这个数组的数据类型及数组的大小,也就是说数组中存放的元素个数固定并且类型一样

②ArrayList是动态数组,也就是数组的复杂版本,它可以动态的添加和删除元素,被称为”集合“,集合的声明如下
ArrayList list = new ArrayList(10);
ArrayList list1 = new ArrayList();
可以看出:在不使用泛型的情况下,这个list是可以添加进不同类型的元素的,而且arraylist是可以不用指定长度的。在使用泛型时,我们就只能添加一种类型的数据了


23.springbean循环依赖以及解决方案

循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。

是在A类中通过A类的构造函数注入了B类,而在B类中又通过B类的构造函数注入了A类导致的Spring Bean循环依赖问题。

简明扼要的说,就是——不使用基于构造函数的依赖注入。可通过下面方式解决。

在字段上使用@Autowired注解,让Spring决定在合适的时机注入。【推荐】

基于setter方法的依赖注射取代基于构造函数的依赖注入来解决循环依赖。

24.jvm双亲委派机制

要了解双亲委派机制得先了解个概念:

类加载器:“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块成为“类加载器”。

通俗的讲,虚拟机是根据类的全限定名来加载类的,那么有个问题,如果同时存在两个或多个全限定名完全一致的情况下。该如何选择加载哪个类。这就是双亲委派机制要做的工作。

在这里强加个知识点:比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有真正的意义,否则,即使这两个类来源于同一个class文件,被同一个虚拟机加载,只要加载他们的类加载器不同,那这两个类就必定不相等。

回到双亲委派的问题上,接下来了解下类加载器的种类:

1-启动类加载器,负责加载%JAVA_HOME%\bin目录下的所有jar包,或者是-Xbootclasspath参数指定的路径;

2-扩展类加载器:负责加载%JAVA_HOME%\bin\ext目录下的所有jar包,或者是java.ext.dirs参数指定的路径;

3-应用程序类加载器:负责加载用户类路径上所指定的类库,如果应用程序中没有自定义加载器,那么次加载器就为默认加载器。

加载器之间的层次关系:

双亲委派机制得工作过程:

1-类加载器收到类加载的请求;

2-把这个请求委托给父加载器去完成,一直向上委托,直到启动类加载器;

3-启动器加载器检查能不能加载(使用findClass()方法),能就加载(结束);否则,抛出异常,通知子加载器进行加载。

4-重复步骤三;

以上就是双亲委派机制的原理。

接下来举个例子:

大家所熟知的Object类,直接告诉大家,Object默认情况下是启动类加载器进行加载的。假设我也自定义一个Object,并且制定加载器为自定义加载器。现在你会发现自定义的Object可以正常编译,但是永远无法被加载运行。

这是因为申请自定义Object加载时,总是启动类加载器,而不是自定义加载器,也不会是其他的加载器。

人和事物都有缺陷,双亲委派机制也不例外,三次得到破坏:

1-jdk1.2之间,用户直接去调用loadClass()方法;不能保证双亲委派机制的基本规则。后改成findClass()方法。

2-双亲委派机制的自我缺陷,使用了线程上下文类加载器。这种行为打破了双亲委派机制模型的层次关系来逆向使用类加载器,实际上违背了双亲委派机制的一般性原则。

3-用户对程序动态性的追求而导致的。例如鼠标,键盘灯热部署。

25.常用名词解释

POJO(Plain Ordinary Java Object): POJO 专指只有 setter / getter / toString的简单类,包括DO/DTO/BO/VO等。

GAV(GroupId、ArtifactctId、Version): Maven坐标,是用来唯一标识jar包。

OOP(Object Oriented Programming):泛指类、对象的编程处理方式。

ORM(Object Relation Mapping): 对象关系映射,对象领域模型与底层数据之间的转换,本文泛指mybatis等框架。​​​​​​​

NPE(java.lang.NullPointerException): 空指针异常。​​​​​​​

SOA(Service-Oriented Architecture): 面向服务架构,它可以根据需求通过网络对松散耦合的粗粒度应用组件进行分布式部署、组合和使用,有利于提升组件可重用性,可维护性。​​​​​​​

IDE(Integrated Development Environment): 用于提供程序开发环境的应用程序,一般 包括代码编辑器、编译器、调试器和图形用户界面等工具,泛指eclipse等。​​​​​​​​​​​​​​

OOM(Out Of Memory): 源于 java.lang.OutOfMemoryError,当JVM 没有足够的内存来为对象分配空间并且垃圾回收器也无法回收空间时,系统出现的严重状况。​​​​​​​

一方库: 本工程内部子项目模块依赖的库(jar包)。​​​​​​​

二方库: 公司内部发布到中央仓库,可供公司内部其它应用依赖的库(jar包)。​​​​​​​

三方库: 公司之外的开源库(jar包)。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_40214674/article/details/116465381

java面试题全集(上)-爱代码爱编程

2013年年底的时候,我看到了网上流传的一个叫做《Java面试题大全》的东西,认真的阅读了以后发现里面的很多题目是重复且没有价值的题目,还有不少的参考答案也是错误的,于是我花了半个月时间对这个所谓的《Java面试大全》进行了

java面试题大全(整理版)_习惯~的博客-爱代码爱编程_java面试题

这几天在网上搜集各种java面试题: 一是为了自己能复习方便,二是为了分享给大家~~题目都是来自网上大佬的分享,感谢大佬们的贡献~~ (持续更新中...) 1、面向对象的特征有哪些方面? - 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。 - 继承:

java面试题及答案2019版(下)_java程序员-张凯的博客-爱代码爱编程_java 面试题

上一篇:Java面试题及答案2019版(上) 51、类ExampleA继承Exception,类ExampleB继承ExampleA。 有如下代码片断: try {     throw new ExampleB("b") } catch(ExampleA e){     System.out.println("ExampleA"); } catch

挑战10个最难回答的java面试题(附答案)_only寒暄的博客-爱代码爱编程

是我收集的10个最棘手的Java面试问题列表。这些问题主要来自 Java 核心部分 ,不涉及 Java EE 相关问题。你可能知道这些棘手的 Java 问题的答案,或者觉得这些不足以挑战你的 Java 知识,但这些问题都是容易在各种 Java 面试中被问到的,而且包括我的朋友和同事在内的许多程序员都觉得很难回答。 1.为什么等待和通知是在 Object

简单java面试题(带答案)-爱代码爱编程

最新公司没什么活,今天项目经理找了一些基础的面试题,下面我把自己回答整理的答案分享一下,可能回答的不够全面,大佬多包涵。 说说以下java关键字的含义 isntanceof trainsient volatile in

面试题总结-爱代码爱编程

ArrayList 和 Vector 的区别。 说说 ArrayList,Vector, LinkedList 的存储性能和特性。 快速失败 (fail-fast) 和安全失败 (fail-safe) 的区别是什么? hashmap 的数据结构。 HashMap 的工作原理是什么? Hashmap 什么时候进行扩容呢? List、Map、Set 三个接口,

Java面试题大全(2021版)-爱代码爱编程

发现网上很多Java面试题都没有答案,所以花了很长时间搜集整理出来了这套Java面试题大全,希望对大家有帮助哈~ 本套Java面试题大全,全的不能再全,哈哈~ 博主已将以下这些面试题整理成了一个Java面试手册,是PDF版的。 关注博主的微信公众号:Java团长,然后回复“面试手册”即可获取~ 一、Java基础知识面试题 1、Java概述 ①.

100道最新Java面试题,常见面试题及答案汇总-爱代码爱编程

除了掌握扎实的专业技能之外,你还需要一份《Java程序员面试宝典》才能在万千面试者中杀出重围,成功拿下offer。 小编特意整理了100道Java面试题,送给大家,希望大家都能顺利通过面试,拿下高薪。赶紧码住吧~~文末有福利 Q1:Java内部类和子类之间有什么区别? 答案:内部类是指在一个外部类的内部再定义一个类,内部类对外部类有访问权限,可以访问

java面试题-基础篇(万字总结,带答案,面试官问烂,跳槽必备)-爱代码爱编程

👀个人主页: Java李小立后面会持续更新java面试专栏,请持续关注如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连❤️❤️❤️) 面试宝典列表(持续更新): 序号内容链接地址1Java基础篇(点击跳转)java面试宝典-基础篇2Java集合框架篇(点击跳转)java面试宝典-集合框架篇3Java多线程篇(点击跳转)java面试宝典- 多

2021 Java面试题大全(整理版)1000+面试题附答案详解,最全面详细,看完稳了!-爱代码爱编程

进大厂是大部分程序员的梦想,而进大厂的门槛也是比较高的,所以这里整理了一份阿里、美团、滴滴、头条等大厂面试大全,其中概括的知识点有:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、 Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka

105道Java面试题,认真思考对你面试很有价值!-爱代码爱编程

一、Java基础 1、什么是面向对象? 2、JDK JRE JVM 3、==和equals比较 4、hashCode与equals 5、final 6、String、StringBuffer、StringBuilder 7、重载和重写的区别 8、接口和抽象类的区别 9、List和Set的区别 10、ArrayList和LinkedLis

java虚拟机怎么安装步骤,详解系列文章-爱代码爱编程

主备同步的实现原理 我们先来了解一下主备同步的原理,下面以一个update语句来介绍主库与备库间是如何进行同步的。 上图是一个update语句在节点A执行,然后同步到节点B的完整流程图,具体步骤有: 主库接受到客户端发送的一条update语句,执行内部事务逻辑,同时写binlog。备库通过 change master 命令,设置主库的IP、端口、

Java面试题及答案整理(2021最新版)-爱代码爱编程

《Java 最常见的 208 道面试题》的答案已经全部更新完了,有些答案是团长自己总结的,也有些答案是在网上搜集整理的。这些答案难免会存在一些错误,仅供大家参考。如果发现错误还望大家多多包涵,不吝赐教,谢谢~ 团长特意整理出这个目录,方便大家平时复习和收藏哈。希望正在准备面试的朋友们能顺顺利利找到自己心仪的工作,加油!!! 1、Java 最常见的 20

java面试题汇总(中)-爱代码爱编程

前言   上篇文章给大家介绍了java后端研发中常见的面试题,我们将java面试的技能树大致分为了十九个模块。并且给出了初学者在java学习的时候,应该如何学习这些技能以及这些技能学习的先后顺序以及技术栈,防止初学者走弯路而放弃。本文开始针对上一篇文章的问题,给大家每一道面试题给出我认为比较正确的答案,有的是自己想的,有的是从网上摘录别人回答的答案。可能

JVM调优到底是什么,面试官为什么那么喜欢问-爱代码爱编程

我是觉得现在不少公司面试Java程序员就盯着jvm问,是种舍本逐末。而我最不能忍的就是好多程序员解决问题喜欢一杆子捅到底层,遇到问题竟然会先想是不是JVM的bug,遇到延时高就会断定是gc算法有问题,竟然会先去考虑替换gc算法,这种自信我也是挺醉的。 那么真有那么多项目要调优吗? 一般项目肯定是不需要进行 JVM 调优的,因为 JVM 本身就是为这种低