解析

323 阅读17分钟

java基础

1. HashMap的源码,实现原理,JDK8中对HashMap做了怎样的优化?

为了处理hash冲突出现的列表太长,当链表长度超过8时,链表转为红黑树

2. HashMap的扩容是怎样扩容的,为什么是2的N次幂的大小?

初始化阀值的时候,tableSizeFor函数的存在导致肯定是2的倍数 put的时候判断size大于阀值的时候,resize函数扩容,扩容后的大小是原来的两倍,初始化是16,所以一定是2的N次

3. HashMap,HashTable,ConcurrentHashMap的区别

对于数据,加上volatile,读的时候不加锁也能保证最新的值 HashMap:线程不安全,初始值为16,key/value都不可以为null HashTable:线程安全,每次修改数据时候,锁住整个table,key/value都可以为null ConcurrentHashMap:线程安全,在HashMap的基础之上增加了Segment(16个)划分区域,操作该区域数据的时候,上锁

4. java中四种修饰符的限制范围

public>protected>缺省>private

5.接口和抽象类的区别,注意JDK8的接口可以有实现

  1. 接口可以继承多个,类只能继承一个
  2. 接口的函数只能使用public, abstract, default, static and strictfp(浮点型精确计算)修饰
  3. 接口的属性是默认的public final(没有意义)
  4. 接口不能含有静态方法和静态代码块
  5. 抽象类表示的是子类“是不是”属于某一类的子类,接口则表示“有没有”特性“能不能”做这种事
  6. Java8中的接口中的默认方法是可以被多重继承的。而抽象类不行

6.动态代理的两种方式,以及区别

  1. JDK动态代理和cglib动态代理
  2. JDK使用了Proxy和InvocationHandler。调用Proxy类中的newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法可以创建一个动态代理对象,但是这个方法需要3个参数,前两个参数是固定的,但第三个参数比较麻烦,需要我们创建一个类MyInvocationHandler来实现InvocationHandler接口,这个类里面要重写invoke()方法。
  3. 区别:JDK必须是接口代理,cglib是继承代理,针对对象代理,不可以使用final修饰。

7.Java序列化的方式

  1. 通过实现Serializable接口,这种是隐式序列化(不需要手动),这种是最简单的序列化方式,会自动序列化所有非static和 transient关键字修饰的成员变量
  2. Externalizable接口继承自Serializable, 我们在实现该接口时,必须实现writeExternal()和readExternal()方法,而且只能通过手动进行序列化,并且两个方法是自动调用的,因此,这个序列化过程是可控的,可以自己选择哪些部分序列化
  3. transient可以禁止属性序列化

8.一个ArrayList在循环过程中删除,会不会出问题,为什么

  1. iterator删除会有问题,删除之后,next指向出问题。
  2. for循环从后往前删没有问题,因为删除之后,前面的数据位置不会变,后面的位置才会变

9.@transactional注解在什么情况下会失效,为什么

  1. @Transactional 注解只能应用到 public 可见度的方法上。 如果应用在protected、private或者 package可见度的方法上,也不会报错,不过事务设置不会起作用。
  2. 默认情况下,Spring会对unchecked异常(继承Error和RuntimeException)进行事务回滚;如果是checked(继承java.lang.Exception)异常则不回滚。自己catch异常之后也不会回滚。
  3. 数据库引擎要支持事务,spring需要开启事务扫描。

10. 事务类型

  1. 7种事务类型 REQUIRED(默认)、NOT_SUPPORTED、REQUIRESNEW、MANDATORY、SUPPORTS、NEVER、NESTED

11.object原生方法和作用

  1. toString、equals、hashCode、getClass、
  2. notify、notifyAll:该对象重新获得对象锁
  3. sleep:不释放对象锁,监听状态保持  wait:释放对象锁

12. 类加载器

  1. 委托、可见性和单一性的原则
  2. Application( CLASSPATH环境变量, 由-classpath或-cp选项定义,或者是JAR中的Manifest的classpath属性定义.)继承Extension(JRE/lib/ext或者java.ext.dirs指向的目录)继承Bootstrap(JRE/lib/rt.jar),从父到子顺序加载。
  3. 子类可以看见父类加载的类,反之不可以
  4. 父加载器加载过的类不能被子加载器加载第二次
  5. class.forname() 通过类名来加载类。

数据结构和算法

1.八大排序

  1. 冒泡
  2. 选择
  3. 插入:插入排序是在一个已经有序的小序列的基础
  4. 基数:
  5. shell:按照不同步长进行插入排序,缩小步长
  6. 快排
  7. 归并
  8. 桶排:hash到桶里面,然后再排序
  9. 堆:根节点比两个子节点都大/小

2.B+树,B-树,红黑树,平衡二叉树

  1. B-树:是一种多路搜索树,从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为空,或已经是叶子结点
  • 定义任意非叶子结点最多只有M个儿子,M>2
  • 除根结点以外的非叶子结点的儿子数为[M/2, M]
  • 所有的叶子节点在同一层
  • 任何一个关键字出现且只出现在一个结点中
  • 非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1]
  • 非叶子结点的关键字个数=指向儿子的指针个数-1
  • 非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树
  1. B+树:B+的搜索与B-树也基本相同,区别是B+树只有达到叶子结点才命中
  • 非叶子结点的子树指针与关键字个数相同
  • 非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树
  • 为所有叶子结点增加一个链指针
  • 所有关键字都在叶子结点出现
  1. 红黑树:是一种弱平衡二叉树,适用于搜索,插入,删除操作较多的情况下
  • 根节点一定是黑色
  • 红色节点不可以两次连续出现
  • 每个叶节点都是黑色的空节点(NIL节点)
  • 从任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点
  1. 完全平衡二叉:适用于插入与删除次数比较少,但查找多的情况
  • 左右子树树高不超过1

3.一致性Hash算法,一致性Hash算法的应用

  1. hash环的引入,顺时针遇到的第一个node
  2. 虚拟节点的引入,解决数据不均匀的问题
  3. 宕机或者增加节点的时候,只有一台服务器的数据受到影响

4.hash碰撞的解决

  1. 链地址法,hashmap就是使用这个方法
  2. 再哈希法 多个hash计算公式
  3. 开放定址法 p产生p1 如果碰撞 p1产生p2,如果碰撞 p2产生p3

5.有限内存海量数据处理

JVM

1. java内存模型和jvm内存结构的区别

  1. java内存模型:指多线程按照一定的模式来运行,内存间的数据交互。涉及主存,缓存,高速缓存,cpu,java中同步的关键字(synchronized、volatile)
  2. jvm内存结构:1.7之后,,取消永久代,方法区的部分变量移动到heap中
  • 线程:本地方法栈、java栈、程序计数器
  • 公共:堆、方法区(类加载信息,常亮,静态变量)、本地方法区

2.内存溢出,内存泄露[www.cnblogs.com/Sharley/p/5…]

  1. 内存溢出 out of memory:是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出
  2. 内存泄露 memory leak:是指程序在申请内存后,后续已经不会使用,但是无法释放已申请的内存空间(gc无法回收),一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

多线程

1.线程池的原理

  1. 刚开始都是在创建新的线程,达到核心线程数量后,新的任务进来后不再创建新的线程,而是将任务加入工作队列,任务队列到达上线后,新的任务又会创建新的普通线程,直到达到线程池最大的线程数量10个,后面的任务则根据配置的饱和策略来处理,AbortPolicy(后面的丢弃直接抛出异常,默认)、CallerRunsPolicy(直接在调用者线程中,运行当前被丢弃的任务)、DiscardOldestPolicy(丢弃队列中添加时间最旧的一个任务)、DiscardPolicy(不处理) 作用:减小资源的消耗,提高响应速度,控制连接数量,防止内存溢出系统奔溃
Executors.newCachedThreadPool();//创建一个可缓存线程池,线程池为无限大,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
Executors.newFixedThreadPool(10);//定长=10的,可控制线程最大并发数,超出的线程会在队列中等待
Executors.newScheduledThreadPool(10);//定长=10的,可周期执行任务的线程池
Executors.newSingleThreadExecutor();//单线程 顺序执行,保证任务的执行顺序
//四大线程池,底层都是去实现ThreadPoolExecutor,只是参数不一样
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                5,//核心线程数量
                10,//最大线程数量
                60,//线程池中超过corePoolSize数目的空闲线程最大存活时间
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(),
                new ThreadPoolExecutor.CallerRunsPolicy());
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                
            }
        });

2. java实现多线程的方式,runnable的优点

  1. 继承runneable接口,继承Thread类,继承Callable
FutureTask future = new FutureTask<>(()->{
            return "succeed";
        });
Thread thread = new Thread(future);
thread.start();
try {
    System.out.println(future.get());
}catch (Exception e) {
    e.printStackTrace();
}
复制代码
  1. 接口避免单继承,runnable可以被多个线程共享,适合多个线程去处理同一个资源。
  2. callable可以有返回值,可以抛出异常。

3.cas乐观锁,悲观锁,syn互斥锁,可重入锁

  1. 乐观锁,应用于多读少写,更新数据的时候,利用version和cas来判断数据是否更改过,不加锁,失败的话,自旋直到成功。有ABA的bug
  2. 悲观锁,应用于多写少读,更新数据的时候,加上锁。
  3. 互斥锁指某一时间只能有一个线程访问修改变量。同步锁指约定一个执行的协调顺序,类似于拓扑排序
  4. 可重入锁指的是,在读取数据的时候,可以多个线程并发读取,写的时候只能有一个线程。

4.锁膨胀和优化(www.cnblogs.com/dsj2016/p/5…)

5.volatile,threadlocal

  1. volatile具有可见性、有序性(防止jvm重排),不具备原子性。使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效(非volatile变量不具备这样的特性。有序性可以保证volatile修饰的语句不可以更改位置,保证之前的都被执行。
  2. threadlocal是指某个线程的本地存储,生命周期。

数据库

1.常见的数据库优化手段

  1. www.jianshu.com/p/dac715a88…

2.索引

  1. 索引是对某一个或者多个字段进行排序,便于查找。主键索引,普通索引,唯一索引,组合索引,全文索引,聚簇索引(物理索引只能有一个)
  2. 索引方法   hash:适合 = in <=>的查询   B-tree:经过排序,适合范围查询
  3. 查询优化器来自动选择索引,索引不建议太多。

3.引擎

  1. innodb:默认的,支持事务,行锁,能够有效处理巨大数据量。
  2. MyISAM:不支持事务,提供高速存储和检索,提供全文搜索的能力。
  3. memory:存放在内存中的表,不支持事务。
  4. federated:用于远程表的映射,可以看成是软连接

4.sql查询慢,如何排查

查看每个环节花费的时间,语句的执行顺序,索引

计算机网络

1.tcp和udp,三次挥手,四次挥手。

  1. tcp不会丢失数据,面向字节流,一对一。分长连接和短连接。Rpc基于tcp长连接协议。
  2. udp可能丢数据,不会阻塞,面向报文,一对多,用于实时的,对话,视频等。

2.实现udp的可靠传输

  1. 不可靠因素:不保证消息交付、不保证交付顺序、不跟踪连接状态、不需要拥塞控制
  2. 在udp协议的基础上,修改上述因素提出的需求

3.长连接和短连接,连接池适合哪一种

  1. 长连接和短连接都是tcp模式,由于连接需要消耗资源,连接池更加适合长连接

4.http和https的区别

  1. https=http+ssl 多了一个加密证书,不对称加密

5.io和nio

  1. io是面向流的阻塞,nio是面向缓存的非阻塞,通过选择器select来管理多了通道。filechannel是不可以的,socketChannl可以,因为继承了AbstractSelectableChannel

6.CDN的全称是Content Delivery Network,即内容分发网络,尽可能走不拥堵的网络

  1. 包括分布式存储、负载均衡、网络请求的重定向、内容管理
  2. CDN网络是在用户和服务器之间增加Cache层

7.进程之间的通行方式,区别

  1. 无名管道:linux中的一种通信方式
  • 半双工的,类似于队列,数据流是有方向的
  • 只能用于有亲缘关系的进程之间的通行
  • 只存在于内存中
  1. FIFO
  • FIFO可以在无关的进程之间交换数据,与无名管道不同
  • 它以一种特殊设备文件形式存在于文件系统中
  1. 消息队列
  • 独立于进程之外,进程终止时,消息队列及其内容并不会被删除
  • 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取
  1. 信号量
  • 锁的概念,用于进程间的同步,也可以用于进程之间的同步顺序
  • 如果有数据传递,需要结合内存共享
  1. 共享内存
  • 共享内存是最快的一种 IPC,因为进程是直接对内存进行存取
  • 因为多个进程可以同时操作,所以需要进行同步
  • 信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问

设计模式(www.cnblogs.com/geek6/p/395…)

1.单例模式:DAO,service

  1. 饿汉式
    //volatile可以禁止重排序,保证线程安全
    private volatile static TestSingleInstance testSingleInstance;

    private TestSingleInstance() {
    }

    public static TestSingleInstance getInstance() {
       if (testSingleInstance == null) {//不加的话 由于每次都需要同步加锁,效率狠低
            synchronized (testSingleInstance) {
                if (testSingleInstance == null) {
                    testSingleInstance = new TestSingleInstance();
                }
            }
        }
        return testSingleInstance;
    }
}
复制代码
  1. 饱汉式
    private static TestSingleInstance testSingleInstance = new TestSingleInstance();

    private TestSingleInstance() {
    }

    public static TestSingleInstance getInstance() {
        return testSingleInstance;
    }
}
  1. 不用synchronized和lock,实现线程安全的单例模式
public class Singleton {
    private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>(); 
 
    private Singleton() {}
 
    public static Singleton getInstance() {
        for (;;) {
            Singleton singleton = INSTANCE.get();
            if (null != singleton) {
                return singleton;
            }
 
            singleton = new Singleton();
            if (INSTANCE.compareAndSet(null, singleton)) {
                return singleton;
            }
        }
    }
}

2.代理模式:spring中的apo,使用代理

  1. jdk代理,对于有接口的,创建代理类
public class TestProxy implements InvocationHandler{

    private Target target;

    public TestProxy() {
    }

    public TestProxy(Target target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy");
        return method.invoke(target,args);
    }

    public static Target getInstance(Target object) {
        return (Target) Proxy.newProxyInstance(object.getClass().getClassLoader(),
                object.getClass().getInterfaces(),
                new TestProxy((Target) object));
    }
    public static void main(String[] args) {
        Target t = TestProxy.getInstance(new TargetImpl());
        t.save();
    }
}

interface Target {
    public void save();
}
class TargetImpl implements Target{

    @Override
    public void save() {
        System.out.println("save");
    }
}
复制代码
  1. 继承的方式来实现动态代理,final修饰的方法无法被代理
public class TestCglib {
    public void save() {
        System.out.println("save");
    }

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(TestCglib.class);//设置被代理类
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("before");
                methodProxy.invokeSuper(o,objects);//调用父类的方法,由于是根据方法名去调动的
                System.out.println("after");
                return null;
            }
        });
        TestCglib testCglib = (TestCglib) enhancer.create();
        testCglib.save();
    }
}
复制代码

3.策略模式:加载资源文件的时候 FileSystemResource等都有共同的接口Resource

  1. 一个类包含一个属性=一个接口。这个接口有多个实现类,根据实现类的不同,调用不用的方法。

4.适配器模式:

  1. 新建类/接口继承相同的接口
  2. 类的适配器:将一个类转换成满足另一个新接口的类时,创建一个新类,继承原有的类,实现新的接口即可。
  3. 对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。
  4. 接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。

5.装饰器模式:

  1. 新建装饰类,包含需要被装饰的对象
  2. 动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)

6.观察者模式:listener类

  1. 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新

分布式

1.分布式锁

  1. 锁,只需要所有线程都能看到标记。分布式的情况下,多进程的情况下,设置一个大家都能看的到的信号就可以。
  2. 基于数据库主键唯一的锁(插入获得锁,删除释放锁),基于数据库表的版本号(并发情况下,开销很大)
  3. 基于redis,在redis中存放全局标志。

2.分布式session:基于各种共享数据

  1. 给予redis,memcache等的分布式session

缓存

1.redis和memcache的区别

  1. redis可以持久化,memcache不可以
  2. memcache可以缓存图片、视频等非文本文件
  3. 都支持集群,memcache使用客户端分布式,redis使用了node节点来实现集群。

2.redis(juejin.im/post/5c6ecc…)

高并发

1.nginx策略

2.负载均衡

框架相关

一、 spring-basic

1.aop

  1. @aspect定义切面
  2. @pointcut表达式和签名,签名可以或与结合使用
  3. 表达式的构成[blog.csdn.net/tiglle/arti…]
  4. 切面的使用原理是反向代理。根据有没有接口,自动实现jdk代理(默认)和cglib代理。

2.ioc的创建和销毁

  1. 在使用spring+springMVC框架的时候,注意spring的ioc容器包含了springMVC的容器。
  2. ioc容器中的bean在程序启动的时候创建,默认使用单例模式,存活到ioc容器被销毁。使用scope模式,会每次都重新生成一个新的对象实例,之后容器就不在拥有当前返回对象的引用。
  3. 如果bean实现了ApplicationContextAware接口,可以获取到上下文(获取到ioc容器)
  4. 通过类加载器,根据类名通过反射获得类,然后创建实例。

3.自启动

  1. 继承CommandLineRunner,实现run方法

二、mybatis的配置

  1. github的Pagehelp的使用:产生分页参数,被第一个查询语句消费。分页信息存储在ThreadLocal中。
  2. #{}是预编译处理,${}是字符串替换。
  3. 主键回显,useGeneratedKeys:开启主键回写,keyProperty:主键对应的属性名(实体中的属性名),keyColumn:主键列名(既数据库表中的列名)
  4. 通过来映射字段名和实体类属性名的一一对应的关系。
  5. insertBatch会去调用insert接口

三、springCloud

  1. eureka:客户端主动注册,轮询心跳,客户端缓存;service节点之间通过复制保证数据的一致性。
  2. ribbon/fegin:负载均衡器
  3. zuul:网关,配置文件配置转发
  4. hystrix:
@FeignClient(name = "dsc-community",fallbackFactory = CommunityClientFallbackFactory.class)
public interface CommunityClient {
}
1、正对接口,编写实现类,用于熔断时候执行
public class CommunityFeignClientWithFactory implements CommunityClient {
}
2、继承FallbackFactory接口,create方法中新建熔断后的处理实例类
@Component
public class CommunityClientFallbackFactory implements FallbackFactory<CommunityClient> {

	@Override
	public CommunityClient create(Throwable arg0) {
		return new CommunityFeignClientWithFactory();
	}

}
  1. config