java

毕业一年后,趁工作闲暇之余整理一些Java面试题,上传到网上纯粹当做笔记,有错欢迎指出 --(2)

java基础篇

一、JDK 和 JRE 有什么区别?
jdk:java开发工具包,包含jre,jre中包含jvm
jre:java运行环境
jvm:jre的一部分,他是整个java实现跨平台的最核心部分,负责解释执行Java字节码文件,是运行java字节码文件的虚拟计算机,java跨平台的原因:Java源文件被虚拟机编译成字节码文件后,生成的是与平台无关的字节码,这些字节码只面向于jvm,不同平台的jvm都是不同的,但是他们都提供了相同的接口
jvm执行过程:1.加载.class文件 2.运行.class文件
二、java中 == 与equals区别 ?
== 如果比较的两个操作数是数值类型,即使他们的数据类型不相等,只要他们的值相等也将返回true,如果比较的是引用类型的话则比较的是地址是否相等。
equals比较的是object类的方法如果不重写equals的话那么比较的就是直接调用的==进行比较,一般equals都是要被重写的,所以关注的是有没有重写equals方法
三、两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
不一定,Java开发中有几个约定:两个对象调用equals返回true,那么对象的hashcode必须返回相同的结果,二两个对象用equals返回false,但是不要求hashcode返回false,但是为了哈希表的性能最好返回不同值,重写equals方法必须重写hashcode,从而保证equals相同的两个对象返回相同的hashcode
四、final 在 java 中有什么作用?
1.修饰类。类不可以被继承
2.修饰方法,方法不能被重写,但是可以被重载
3.修饰基本数据类型的变量,变量只能一次赋值后不能修改,修饰引用类型变量后,也就是修饰一个对象,引用初始化以后永远指向一个内存地址不可修改,但是内存中保存的对象信息是可以修改的。
五、java 中操作字符串都有哪些类?它们之间有什么区别?
String,StringBuffer线程安全,StringBulider线程不安全
六、如何将字符串反转?
1.调用字符串的reserve方法
2.new一个char数组,然后拿到每一个字符,调用字符串的chatAt方法拿到每一个索引的字符,存放到char数组中
七、String类的常用方法?
length,charAt,valueOf,构造方法
八、抽象类必须要有抽象方法吗?
抽象类不一定非要有抽象方法,有抽象方法的一定要是抽象类
九、普通类和抽象类有哪些区别?
普通类可以实例化,抽象类要想实例化必须指向实现所有方法的子类对象
抽象类的抽象方法必须全部被子类实现,如果不能全部实现那么子类也必须是抽象类
十、抽象类可以使用final修饰吗?
不能,因为抽象类是要被继承的,final修饰后不可继承是矛盾的
十一、.java 中 IO 流分为几种?
按照流向分可以分为输入流、输出流
按照操作单元划分为字节流、字符流
InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流
OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流
十二、字节流字符流区别?
字节流是程序的计量单位,字符是应用程序中的字符表示
字节流是直接操作文件的,而字符流操作文件是使用到了缓冲区,通过缓冲区在操作文件,所以在程序中如果没有关闭字符流的操作,缓冲区中的内容是没发输出的,关闭字符流会强制将缓冲区中的内容进行输出。或者使用Writer类中的flush()方法完成内容输出
总结:字节流没有使用缓冲区,而字符流使用到了缓冲区
缓冲区可以理解为一块内存区域,如果程序频繁的操作某一个资源比如数据库,那么性能将会降低,为了提高性能可以将一部分数据暂时存放在内存的一块区域中,以后直接从内存中操作数据即可
由字节流转化为字符流实际上就是操作byte[]转化为String
十三、Files的常用方法有哪些?
Files.exists() 检测文件路径是否存在
Files.createFile()创建文件
Files.read() 读取文件
Files.write()写入文件

java容器

一、java 容器都有哪些?
数组,和集合容器
二、Collection 和 Collections 有什么区别?
Collection是集合的顶层接口,其实现类有list和set
Collections是一个操作集合的工具类,里面定义了很多操作集合的静态方法是一个帮助类
三、如何决定使用 HashMap 还是 TreeMap?
TreeMap的key是实现comparable所以迭代是默认按照key值迭代升序排列的,TreeMap底层是红黑树数据适用于自然排序
HashMap的key值是实现散列hashcode,分布是随机的不支持排序,底层数据结构是数组或者链表,适合在map中插入,删除和定位元素
结论:如果需要得到一个有序的结果的时候就使用TreeMap,其他情况使用HashMap,HashMap拥有比较好的性能
四、说一下 HashMap 的实现原理?HashSet 的实现原理?
结合HashMap的put/get方法进行研究(记住HashMap的几个默认值如,默认长度为16,动态扩容时负载因子为0.75,扩容方式为二倍扩容),hashSet底层是由HashMap实现的,只不过将HashMap的value值写死为定值
五、.ArrayList 和 LinkedList 的区别是什么?
1.ArrayList是动态数组的实现,而LinkedList是双向链表的实现
随机访问效率中ArrayList效率要高于LinkedList,前者根据索引而后者需要移动指针
综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。
2.对ArrayList的源码分析


public boolean add(E var1);//默认在末尾直接添加元素
public boolean add(E var1) {
	//先判断内部容量是否足够了,size是数组中数据的个数,因为要添加一个元素所以size+1
	//判断size+1这个数,数组中是否放的下,若数组是个空的数组则分配默认空间为10的长度
	//如果size+1大于10这个长度,那么就说明elementData数组的长度不够用,那么就要增加
	//elementData的length,调用grow方法,进行自动扩展ArrayList的大小
	this.ensureCapacityInternal(this.size + 1);
	this.elementData[this.size++] = var1;
	return true;
}
扩容

private void grow(int minCapacity) {
    // overflow-conscious code
    //将扩充前的elementData大小给oldCapacity
    int oldCapacity = elementData.length;
    //newCapacity就是1.5倍的oldCapacity,因为向右移1位代表除以2
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        //这句话就是适应elementData空数组的时候,length=0,那么oldCapacity=0,newCapacity=0,所以这个判断成立,在这里就是真正的初始化elementData的大小了,前面的工作都是准备工作。
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        //如果newCapacity超过了最大的容量的限制,就调用hugeCapacity,也就是能给的最大值给newCapacity
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    //新的容量大小已经确定好了,就copy数组,改变容量大小
    elementData = Arrays.copyOf(elementData, newCapacity);
}

六、.如何实现数组和 List 之间的转换?
数组转List: Arrays.stream(str).collect(Collectors.toList());或者Arrays.asList,但是这种方法是不能对集合进行新增和删除操作的
集合转数组:直接new一个数组,调用集合的toArray方法,构造方法里面传入集合大小
七、.ArrayList 和 Vector 的区别是什么?
Vector是线程安全的,扩容方式100%的扩容
ArrayList线程不安全,扩容方式50%的扩容
如过在集合中使用数据量比较大的数据或者多线程的话,用vector有一定的优势
八、Array 和 ArrayList 有何区别?
定义一个数组的时候必须指定数组的长度和数据类型
ArrayList是动态数组,长度动态可变,会自动扩容,不使用泛型的时候可以添加不同类型元素
九、哪些集合类是线程安全的?
vector、hashtable、ConcurrentHashMap
十、迭代器 Iterator 是什么?
Iterator对集合类中的任何一个实现类,都可以返回这样一个Iterator对象。可以适用于任何一个类
迭代器是可以遍历集合的对象,为各种容器提供了操作集合的接口,迭代器与集合类成对增加,用于顺序访问集合对象的元素,无需知道对象的底层实现
十一、使用for循环还是迭代器Iterator对比
采用ArrayList对随机访问比较快,而for循环中的get()方法,采用的即是随机访问的方法,因此在ArrayList里,for循环较快
采用LinkedList则是顺序访问比较快,iterator中的next()方法,采用的即是顺序访问的方法,因此在LinkedList里,使用iterator较快
for循环适合访问顺序结构,可以根据下标快速获取指定元素.而Iterator 适合访问链式的顺序结构,因为迭代器是通过next()和Pre()来定位的.可以访问没有顺序的集合
十二、Iterator 怎么使用?有什么特点?
Iterator配合集合使用,使用 hasNext 检查集合中是否还有元素 和 next 方法获得集合中的下一个元素,遍历
特点:Iterator遍历元素的过程中不允许对元素进行修改,否则会抛出ConcurrentModificationEception并发修改的异常,因为在Iterator底层实现中存在两个变量modCount和expectedModCount 必须相等,所以不能使用list集合的remove方法,(借鉴网上说法)Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变。当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出java.util.ConcurrentModificationException 异常。所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。应该使用iterator自带的remove,移除后并没有return,而是重新维护了索引,使得两个常量有重新相等Iterator遍历集合元素的过程中可以通过remove方法来移除集合中的元素
十三、Iterator和 ListIterator有什么区别?
ListIterator 继承 Iterator,所以他比 Iterator方法多
使用范围不同,Iterator可以迭代所有集合;ListIterator 只能用于List及其子类
ListIterator 有 add 方法,可以向 List 中添加对象;Iterator 不能
ListIterator 有 set()方法,可以实现对 List 的修改;Iterator 仅能遍历,不能修改
十四、怎么确保一个集合不能被修改?
使用Collections类的unmodifiable方法赋值原来的集合即可

多线程

一、并行和并发有什么区别?
并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
并发是交替做不同事情的能力,而并行是同时做不同事的能力
二、线程和进程的区别?
1.进程是一段正在执行的程序,是资源分配的基本单元,而线程是CPU调度的基本单元
2.进程之间相互独立,不能共享资源
3.线程是进程的一部分
三、守护线程是什么?
守护线程,是一个服务线程,准确的来说就是服务其他线程,其他线程就是只有一种就是用户线程,所以Java中线程分为两类
1.守护线程,比如垃圾回收线程
2.用户线程,应用程序里面的自定义线程
换一种说法,就是当用户自定义线程还没有结束,jvm就不会退出,当然守护线程也不会退出,因为他要进行垃圾回收任务
四、说一下 runnable 和 callable 有什么区别?
1.实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;
2.Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛
互斥锁是一种简单的加锁的方法来控制对共享资源的访问
五、线程有哪些状态?
新建-就绪-运行-阻塞-死亡
1.新建状态:当用new操作符新建一个线程时,线程此时处于新建状态,此时程序还没有开始运行程序中的代码
2.就绪状态:一个新建的线程不自动开始执行,要执行线程,必须调用线程的start方法,start方法返回后线程处于就绪状态,处于就绪状态的线程不一定立即开始运行run方法,此时还要获取cpu的执行权,当获取到CPU的执行权以后,才能开始真正的执行线程的run方法,因为在单CPU的计算机操作系统中,是不允许同时运行多个线程的,一个时刻只能有一个线程运行,因此此时会有许多线程处于就绪状态
3.运行状态:当线程获得到CPU执行权后,他才进入运行状态,开始执行真正的run方法
4.阻塞状态:线程在执行过程中,可能由于各种原因进入阻塞状态。如:调用sleep方法进入睡眠状态,试图得到一个锁,但是这个锁正在被其他线程锁持有,所谓阻塞状态就是正在运行的线程没有运行结束,暂时让出CPU的执行权,这时处于就绪状态的线程就可以获取CPU时间进入运行状态
5.死亡状态:run方法正常退出死亡,未捕获的异常终止run方法导致线程猝死。可以使用isAlive方法。如果是可运行或被阻塞,这个方法返回true;如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false
六、sleep() 和 wait() 有什么区别
sleep方法就线程Thread类的静态方法,调用该方法使线程进入睡眠状态,让出执行机会给其他线程,等待休眠结束后进入就绪状态然后再和其他线程一起争夺cpu执行权,因为是线程类的静态方法,所以当在一个synchronized块中调用了sleep方法,线程虽然进入了休眠但是没有释放锁,其他线程仍然无法访问这个对象
wait是Object类的一个方法,当一个线程执行到wait方法时,会释放一个对象的锁,使得其他线程能够访问,可以通过notify或者notifyAll方法唤醒等待中的线程
综上所述:sleep() 和 wait() 的区别就是 调用sleep方法的线程不会释放对象锁,而调用wait() 方法会释放对象锁
七、notify()和 notifyAll()有什么区别?
1.先了解两个概念,锁池和等待池
锁池:假设线程A已经拥有了某个对象的的锁,注意:不是类,而其他线程想要进入对象的synchronized方法之前必须先要获取对象的锁的拥有权,但是该对象的锁目前正被线程A持有,所以这些对象就进入了对象的锁池中
等待池:假设线程A调用了对象的wait方法,线程A释放了对象的锁后,就进入了该对象的等待池中,等待池中的线程不会竞争该对象的锁
2.当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
八、线程的 run()和 start()有什么区别?
start方法是用来启动线程执行的,当线程获取cpu执行权时,会自动调用run方法,所以start()调用结束并不表示相应线程已经开始运行,这个线程可能稍后运行,也可能永远也不会运行。
而直接调用run方法无法达到启动多线程的目的,相当于主线程线性的执行多线程的run()方法。
九、创建线程池的几种方式
Executors提供了几种创建线程池的创建配置
1.newFixedThreadPool:固定大小的线程池,可以指定线程池的大小,该线程池corePoolSize和maximumPoolSize相等,阻塞队列使用的是LinkedBlockingQueue,大小为整数最大值
2.newSingleThreadExecutor:单个线程线程池,只有一个线程的线程池,阻塞队列使用的是LinkedBlockingQueue,若有多余的任务提交到线程池中,则会被暂存到阻塞队列,待空闲时再去执行。按照先入先出的顺序执行任务
3.newCachedThreadPool:缓存线程池,缓存的线程默认存活60秒。线程的核心池corePoolSize大小为0,核心池最大为Integer.MAX_VALUE,阻塞队列使用的是SynchronousQueue。是一个直接提交的阻塞队列
4.newScheduledThreadPool:定时线程池,该线程池可用于周期性地去执行任务,通常用于周期性的同步数据
十、线程池都有哪些状态?
1.RUNNING,这是最正常的状态,接受新的任务,处理等待队列中的任务。线程池的初始化状态是RUNNING。线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0
2.SHUTDOWN,不接受新的任务提交,但是为继续处理等待中的任务,调用线程池的shutdown方法时,线程池由running状态转为shutdown
3.STOP.不接受新的任务提交,不在处理等待中的任务,中断正在执行任务的线程,调用线程池的shutdownNow方法时,线程池变为stop
4.TIDYING。所有任务都销毁,线程池的状态在转换为 TIDYING 状态
5.TERMINATED。线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。
十一、线程池中 submit()和 execute()方法有什么区别?
execute() 没有返回值;参数Runnable,没有返回值无法确定任务是否完成
submit() 有返回值,参数runnable或者callable,submit() 的返回值 Future 调用get方法时,可以捕获处理异常
十二、在 java 程序中怎么保证多线程的运行安全?加锁机制synchronized
线程安全的问题体现在:
原子性:一个或者多个操作在 CPU 执行的过程中不被中断的特性
可见性:一个线程对共享变量的修改,另外一个线程能够立刻看到
有序性:程序执行的顺序按照代码的先后顺序执行
解决:
JDK Atomic开头的原子类、synchronized、LOCK,可以解决原子性问题
synchronized、volatile、LOCK,可以解决可见性问题
Happens-Before 规则可以解决有序性问题
十三、什么是死锁?
死锁是指两个或者两个以上的进程在执行过程中,由于彼此竞争资源而产生的一种阻塞的现象
死锁的产生的原因:
1.互斥条件:一段时间内一个资源只能由一个进程所占有
2.请求与保持条件:当进程由于请求资源而阻塞时,对以获取的资源保持不放
3.不剥夺条件:进程在资源未使用完成之前,不可剥夺,只能由自己使用完之后由自己释放
预防死锁:
1.一次性分配:一次性分配所有的资源,这样就不会有请求了
2.可剥夺资源:当某进程获得了部分资源,释放已经占有的资源
3.破坏请求保持条件:当进程由于请求资源而阻塞时,释放获取的资源
十四、ThreadLocal 是什么?有哪些使用场景?
ThreadLocal是线程本地存储,每一个线程都创建了一个本地的ThreadLocalMap对象,每一个线程都可以访问自己Map对象里的value,通过这种方式避免资源在多线程之间的共享
get()方法是用来获取ThreadLocal在当前线程中保存的变量副本,set()用来设置当前线程中变量的副本,remove()用来移除当前线程中变量的副本
1.经典的使用场景是为每个线程分配一个 JDBC 连接 Connection。这样就可以保证每个线程的都在各自的 Connection 上进行数据库的操作,不会出现 A 线程关了 B线程正在使用的 Connection,
2.session管理
十五、synchronized 和 volatile 的区别是什么?
1.volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
2.volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
3.volatile是变量之间的线程共享,synchronized则通过加锁的机制实现线程安全
自定义线程池的实现:
ThreadPoolExecutor 线程池中最核心的一个类

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory);

参数分析:
1.corePoolSize:线程池核心池大小,当创建线程池后,线程池默认没有任何线程,当有任务过来时才会有创建线程执行任务。精炼的说就是表示线程池中允许同时运行的最大线程数
2.maximumPoolSize:线程池中允许的最大线程数
3.keepAliveTime:表示线程没有任务时最多保持多久然后停止
4.unit:keepAliveTime的单位
5.workQueue:一个阻塞队列,用来存储等待执行的任务,当线程池中线程数超过他的corePoolSize时,线程进入阻塞队列进行等待
6.threadFactory:线程工厂用来创建线程
7.handler :表示当拒绝处理任务时的策略。
流程:任务进来时,首先执行判断,判断核心线程是否处于空闲状态,如果不是,核心线程就先就执行任务,如果核心线程已满,则判断任务队列是否有地方存放该任务,若果有,就将任务保存在任务队列中,等待执行,如果满了,在判断最大可容纳的线程数,如果没有超出这个数量,就开创非核心线程执行任务,如果超出了,就调用handler实现拒绝策略。
handler:表示当拒绝处理任务时的策略,有以下四种取值

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 ;

JVM

一、说一下 jvm 的主要组成部分?及其作用?
1.类加载器class loader,加载类文件到内存,class loader只负责加载,只要符合文件结构就加载,至于能否运行他不负责,由执行引擎Execution Engine负责
2.执行引擎Execution Engine,负责 解释命令,交由操作系统执行,执行class中的指令
3.本地库接口,融合不同的语言为Java所用,与本地库交互
4.运行时数据区:又叫做java内存模型,分为程序计数器,Java堆,虚拟机栈,本地方法栈,方法区包括运行时常量池
运行时常量池是方法区的一部分,主要负责存放预编译时期生成的各种字面量与符号引用,运行时可以将新的常量放入池中,符号引用是指用一组符号来描述引用的目标,而不是地址描述引用的目标
二、.说一下堆栈的区别?
栈内存首先是一块内存区域存储着局部变量,方法的引用等,在方法中定义的都是局部变量,在方法外的都是全局变量,在for循环中也是局部变量,是先加载函数再加载局部变量,所以方法肯定是先进栈,然后再定义变量,变量都有自己的作用域,变量的作用域可以分为类级,方法级,块级,所以一旦离开作用域,变量就会被释放,栈内存的的更新速度都很快,所以局部变量的声明周期都很短。
堆内存:存放的是数组和对象,凡是new出来的都是建立在堆中,堆中存放的是对象实体,实体中存放多个数据,就算数据消失,对象也不会消失,不像栈一样,函数走完,栈内存就会释放空间,堆中的存放的实体虽然不会释放但是会被jvm的垃圾回收机制进行回收
三、队列和栈的区别?
队列:先进先出,是限定只能在表的一端进行插入和另一端删除操作的线性表
栈:先进后出,是限定之能在表的一端进行插入和删除操作的线性表
四、什么是双亲委派模型?
当需要加载一个类的时候,子类加载器并不会马上去加载,而是依次去请求父类加载器加载,一直往上请求到最高类加载器:启动类加载器。当启动类加载器加载不了的时候,依次往下让子类加载器进行加载。当达到最底下的时候,如果还是加载不到该类,就会出现ClassNotFound的情况。
类加载器:启动类加载器,扩展类加载器,应用类加载器,自定义类加载器
五、说一下类加载的执行过程?
1.加载:获取类的二进制字节流,将其静态存储结构转化为方法区的运行时数据结构
2.校验:文字格式验证,字节码的验证
3.准备:在方法区对类的static变量分配内存并设置类变量数据类型默认的初始值,基本数据/引用类型数据
4.解析:将常量池内的符号引用替换为直接引用的过程
符号引用以一组符号(任何形式的字面量(定位代码的变量),只要在使用时能够无歧义的定位到目标即可)来描述所引用的目标。
直接引用通过对符号引用进行解析,找到引用的实际内存地址
5.初始化:为类的静态变量赋予正确的初始值,执行静态语句块、执行构造函数
六、怎么判断对象是否可以被回收?
引用计数器:引用计数器:为每个对象创建一个引用计数,当有对象引用时,计数器+1,当引用释放时,计数器-1,所以,当计数器为0时,就认为可以被回收。
可达性分析:可达性分析 从GC Roots开始向下搜索,搜索所走过的路径称为引用链。 当一个对象到GC Roots没有任何引用链时,则认为此对象可以被回收
七、java 中都有哪些引用类型?
1.强引用(strongreference)就是指在程序代码之中普遍存在的,类似“Object obj=new Object()” 这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象实例。当内存不足时,宁愿抛出OutOfMemeryError异常也不会通过回收强引用的对象,因为JVM认为强引用的对象是用户正在使用的对象,它无法分辨出到底该回收哪个,强行回收有可能导致系统严重错误

2.软引用(softreference)如果一个对象只有软引用,那么只有当内存不足时,JVM才会去回收该对象,其他情况不会回收。软引用可以结合ReferenceQueue来使用,当由于系统内存不足,导致软引用的对象被回收了,JVM会把这个软引用加入到与之相关联的ReferenceQueue中。

3.弱引用(weakreference)也是用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱 引用关联的对象实例只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时, 无论当前内存是否足够,都会回收掉只被弱引用关联的对象实例。在 JDK 1.2 之 后,提供了 WeakReference 类来实现弱引用。

4.虚引用(phantomreference)也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象 实例是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用 来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象 实例被收集器回收时收到一个系统通知。在 JDK 1.2 之后,提供了 PhantomReference 类来实现虚引用。

八.说一下 jvm 有哪些垃圾回收算法?
··标记-清除算法:分为两个阶段:标记和清除
在标记阶段从跟对象开始遍历,对跟对象可以访问到的对象都打上一个标识,一般都是在对象的堆中,被标记后的对象,将其记录为可达对象。
在清除阶段,collector对从头到尾进行线性遍历,如果发现某个对象没有标记为可达对象-通过读取对象的堆信息,将其回收
··标记-整理算法
标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存

九、说一下 jvm 有哪些垃圾回收器?
CMS,G1
···CMS(Concurrent Mark Sweep) 收集器: 是一种以获得最短回收停顿时间为目标的收集器,标记清除算法,运作过程:初始标记,并发标记,重新标记,并发清除,收集结束会产生大量空间碎片,CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用
··G1收集器: 标记整理算法实现,运作流程主要包括以下:初始标记,并发标记,最终标记,筛选标记。不会产生空间碎片,可以精确地控制停顿。
G1收集器收集范围是老年代和新生代,不需要结合其他收集器使用;
十、新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?
新生代回收器:Serial、ParNew、Parallel Scavenge
老年代回收器:Serial Old、Parallel Old、CMS
整堆回收器:G1
新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;老年代回收器一般采用的是标记-整理的算法进行垃圾回收。
十一、.简述分代垃圾回收器是怎么工作的?
可以从新生代,老年代下手理解
新生代分为1个Eden区和2个Survivor区(分别叫from和to)默认比例为8:1,一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中。
因为年轻代中的对象基本都是朝生夕死的(80%以上),所以在年轻代的垃圾回收算法使用的是复制算法,复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。

在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。

十二、常用的 jvm 调优的参数都有哪些?idea中compiler中可配置
-Xms s为strating,表示堆内存起始大小
-Xmx x为max,表示最大的堆内存
-Xss64m 设置每个线程的堆栈大小

十三、说一下 jvm 调优的工具?
Jconsole : jdk自带
JProfiler:商业软件
VisualVM:JDK自带

Java web

一、说一下 session 的工作原理?
session的工作原理就是用户在登录成功以后创建session,session创建完成以后,会把sessionID发送给客户端,,客户端在存储在浏览器当中,这样在每次访问服务器的时候都会带着这个sessionID,服务器拿到sessionID后再内存中找到相应的session就可以工作了
二。如果客户端禁止 cookie 能实现 session 还能用吗?
一般情况下,服务器的session的sessionid是通过cookie储存在浏览器的,一旦浏览器禁用了cookie浏览器无法携带sessionid,这样服务器无法识别用户的身份session失效。
可以通过一下方法,继续使用session
1.URL重写,将sessionid追加到原URL参数中,这样访问服务器就携带sessionid了
2.服务器返回的数据中携带sessionid,浏览器发送请求时携带sessionid参数
三、如何避免 sql 注入?
sql注入是一种用户通过一些非法的字符或途径获取到数据库的数据,操作数据库对数据造成危害
1.对进入数据库的字符进行转义处理
2.严格控制对数据库的操作权限,给用户仅仅能工作的最低权限,从而最大限度的减少注入攻击对数据库的危害
四、.session生命周期
session用于存放用户与web服务器之前的对话,即服务器为客户端开辟的存储空间,因为客户端与服务端是无状态的机制,所以session可用于串联服务端与客户端 session存储在服务器内存中(高速存取),当web服务器启动,用户第一次访问web服务器时session创建,访问静态资源不会创建session,如果session在web服务器上长时间没有活动,session将会失效,默认时间二十分钟,或者调用session的invalivate方法
另外HTTP协议是无状态的(就是客户端服务端交互完成后断开连接一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。),Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户,如果客户端将cookie功能禁用,或者不支持cookie,java web提供一种解决方案,URL地址重写,基本原理为将用户的sessionID重写到URL地址中服务器解析重写后的URL获取sessionID

网络

一、localhost和127.0.0.1的区别
localhost本地服务器的意思不会受到网卡协议的限制,不会解析成ip也不会占用网卡,网络资源
127.0.0.1是经过网卡传输的,依赖网卡协议,受到网卡相关协议的限制,使用IP进行访问时,等于本机通过网络再去访问本机,会涉及到网络用户的权限
二、http 响应码 301 和 302 代表的是什么?有什么区别?
301,302都表示重定向成功,由浏览器输入的URL由地址A到地址B的变化
301表示永久性转移,A地址的资源永久性移出不能访问了
302表示暂时性转移,旧地址A资源仍然可以访问
浏览器默认302跳转
三、讲一下http协议,http协议请求消息头里面都有什么参数?cookie里面缓存的有账户信息吗?
超文本传输协议,是一种通信协议,它允许将超文本传输语言从web服务器传送到客户端浏览器
HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。
四、http协议请求消息头里面都有什么参数?
通用信息有三个字段: 请求url, 请求方法, 状态码, 远程地址。
Accept : 指定客户端能够接收的内容类型,是json还是其他
Accept-Language:浏览器用来展示的语言
Accept-Encoding:浏览器客户端用来支持服务器返回内容的编码类型
Connec-Length : 请求头的长度
cookie : 浏览器端cookie。

设计模式

一、说一下你熟悉的设计模式?
单例模式,简单工厂模式,抽象工厂模式,工厂方法模式

二、简单工厂和抽象工厂有什么区别?
工厂模式就是现在有不同类型的几种产品也就是对象,但是最后可以由一个统一的类型进行接收,为了方便解除代码之间的耦合,就委托工厂进行制造这些对象,就是工厂模式
简单工厂是一个工厂对象可以生产很多种产品对象,但是不利于扩展,抽象工厂一个工厂生产一种产品对象,可以横向新增产品品种,只要实现产品对象接口,扩展性强,

框架篇

一、为什么要使用 spring?
1.方便解耦,简化开发。因为通过Spring提供的IOC容器,我们可以将对象之间的依赖关系交由Spring容器管理
2.AOP编程的支持,通过aop的功能,方便进行面向切面的编程,具体体现在事物方面
3.方便程序的测试,Spring对Junit4支持,可以通过注解方便的测试Spring程序
二、spring 有哪些主要模块?
1.Spring Core框架的最基础部分,提供IOC容器,对bean进行管理
2.spring context Context模块提供框架式的Bean访问方式,其他程序可以通过Context访问Spring的Bean资源,相当于资源注入。
3.DAO模块 Spring提供对jdbc的支持,对jdbc进行封装,允许jdbc使用资源,并统一管理jdbc事物
4.Spring ORM 对象关系映射,对常用orm框架的管理和支持,本身不对orm实现,仅对常见的orm框架进行封装,并对其进行管理
5.Spring AOP 提供了符合AOP Alliance规范的面向方面的编程实现。
6.MVC模块 提供了 Web 应用的 Model-View-Controller 全功能实现
三、spring 常用的注入方式有哪些?
1.构造器注入 例如:在userImpl实现类里面 添加userDao入参为构造函数
2.setter方法注入 在userImpl实现类里面 添加userDao入参为setter方法注入
3.基于注解的注入 @Component @Repository @Controller @Service
@Resource注解默认以ByName去找属性名形同的bean的id,如果没有找到就会以byType的方式查找,如果byType查找到多个的话,使用@Qualifier注解(spring注解)指定某个具体名称的bean
@Autowired:默认是以byType的方式去匹配类型相同的bean,@Autowire默认按照对象类型来注入,如果想按照名称注入可以添加@Qualifier属性实现。
四、spring 中的 bean 是线程安全的吗?
Spring容器中的bean本身不具备线程安全的特性,默认 spring 容器中的 bean 是单例的。当单例中存在竞态条件,即有线程安全问题
五、spring 支持几种 bean 的作用域?
五种
singleton:单例模式,在整个Spring IoC容器中,使用 singleton 定义的 bean 只有一个实例
prototype:原型模式,每次通过容器的getbean方法获取 prototype 定义的 bean 时,都产生一个新的 bean 实例
request,session,global session
六、spring 自动装配 bean 有哪些方式?
1.xml配置
2.自动化装配,用到两个注解,组件扫描(ComponentScan):自动发现应用上下文中所创建的bean,自动装配(Autowired):自动满足bean之间的依赖
七、.spring 事务实现方式有哪些?
1.编程式事物管理,在代码中显示的调用提交,回滚
2.声明式事物管理,配置类的形式,AOP的体现,在方法执行前后加入事物管理,建立在AOP功能之上,本质是通过AOP功能对,方法前后进行拦截,将事物处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务
八、说一下 spring 的事务隔离?
读未提交,读已提交,可重复读,串行化
九、说一下 spring mvc 运行流程?
客户端向服务器发送请求,请求被Spring MVC的前端控制器DispatcherServlet拦截,DispatcherServlet对请求的URL进行解析得到请求资源标识符,然后根据uri调用handlerMapping,返回handler给前端控制器,DispatcherServlet 根据获得的 Handler选择一个合适的 HandlerAdapter,提取数据开始执行controller,执行完成以后返回一个modelAndView,这是一个逻辑视图给前端控制器,前端控制器调用视图解析器…
十、spring mvc 有哪些组件?
1.前端控制器(DispatcherServlet)
2.处理器映射器(HandlerMapping)
是用来查找Handler的。在SpringMVC中会有很多请求,每个请求都需要一个Handler处理,具体接收到一个请求之后使用哪个Handler进行处理呢?这就是HandlerMapping需要做的事
3.处理器适配器(HandlerAdapter)
处理handler
4.视图解析器(ViewResolver)
解析逻辑视图
5.拦截器(HandlerInterceptor)
十一、@RequestMapping 的作用是什么?
他是一个用来处理请求映射的注解,用在类或者方法上。
该注解的属性,value:指定请求的实际地址,method:指定请求的method类型
十二、@Autowired 的作用是什么?
@Autowired是一个注解,让bean完成自动装配的工作,默认按类型去装配,配合 @Qualifier 指定按照名称去装配 bean

Spring boot

一、什么是 spring boot?
spring boot 是基于Spring开发的项目的起点,让你尽快的跑起来并且尽可能的减少配置文件,Spring boot只需要非常少的几个配置就可以搭建一个web项目
二、为什么要用 spring boot?
1.简化XML配置,所有配置都是配置类的形式
2.快速整合第三方框架
3.内置web服务器,Tomcat
三、spring boot 核心配置文件是什么?
Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。
application配置文件主要是用于Spring boot项目的自动化配置
四、spring boot 有哪些方式可以实现热部署?
1.模板热部署,在Spring boot项目中,模板引擎页面是默认开启缓存的,如果修改页面内容,刷新页面是得不到修改后的页面的,可以在application.properties中关闭模版引擎的缓存。例如 Thymeleaf的配置 spring.thymeleaf.cache=false
2.使用调试模式Debug实现热部署

mybatis

一、mybatis分页方式
1.mapper文件分页
2.sql分页
3.RowBounds分页
二、mybatis 逻辑分页和物理分页的区别是什么?
物理分页就是数据库本身提供了分页方式,如MySQL的limit,oracle的rownum ,好处是效率高,不好的地方就是不同数据库有不同的搞法
逻辑分页利用游标RowBounds对象分页,ResultSet结果集执行的内存分页,好处是所有数据库都统一,坏处就是效率低。
三、mybatis 有哪些执行器(Executor)?
SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象
作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。
四. MyBatis实现一对一有几种方式?具体怎么操作的? MyBatis实现一对多有几种方式,怎么操作的?
一对一:resultMap里面配置association节点配置一对一的类就可以完成
一对多:通过在resultMap里面的collection节点配置一对多的类就可以完成
现在基本上不用使用配置节点标签这种,直接嵌套查询,查询单表的数据取出外键id然后去查询关联表就行

mysql

一、数据库的三大范式是什么?
1.第一范式强调的列是具有原子性,即列不能分为其他几列
2.首先要满足第一范式,第二范式包含两部分内容,第一表必须有主键,二是非主键字段必须依赖于主键
3.首先是第二范式,非主键必须直接依赖于主键,不能传递依赖
二、如何获取当前数据库版本?
Mysql命令行 select version();
三、说一下 ACID 是什么?
ACID 一般是指数据库事务的ACID
四、char 和 varchar 的区别是什么?
1.char的长度是不可变的,而varchar的长度是可变的
2.char的存取效率要比varchar快的多,因为长度固定,所以方便程序的存储于查找,但是char也是要付出空间代价,因为长度固定所以单独的空格也会暂用空间
3.char的存储方式是,对英文字符(ASCII)占用1个字节,对一个汉字占用两个字节;而varchar的存储方式是,对每个英文字符占用2个字节,汉字也占用2个字节,两者的存储数据都非unicode的字符数据
五、怎么验证 mysql 的索引是否满足需求
使用EXPLAIN 分析表
EXPLAIN列的解释:
1.table:显示这一行的数据是关于哪张表的
2.key: 实际使用的索引,是主键索引还是其他索引
3.Extra:关于MySQL如何解析查询的额外信息
4.ref:显示索引的哪一列被使用了,如果可能的话,是一个常数
索引类型 创建索引:Create Index Xxx
普通索引,这个是最基本的索引
唯一索引,与普通索引类似,但是不同的是唯一索引要求所有的类的值是唯一的,这一点和主键索引一样.但是他允许有空值,
主键索引,不允许有空值
六、事物的隔离级别
读未提交,读已提交,可重复读,串行化
七、说一下 mysql 常用的引擎?
1.MyISAM存储引擎:不支持事务、也不支持外键,优势是访问速度快,对事务完整性没有 要求或者以select,insert为主的应用基本上可以用这个引擎来创建表,查询快
2.InnoDB存储引擎支持事物但是对比MyISAM引擎,写的处理效率会差一些,并且会占用更多的磁盘空间以保留数据和索引
InnoDB存储引擎的特点:支持自动增长列,支持外键约束
八、说一下 mysql 的行锁和表锁?
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高
九、如何做 MySQL 的性能优化?
为搜索字段创建索引。
避免使用 select *,列出需要查询的字段。
选择正确的存储引擎。
十、如何做 mysql 的性能优化?
1.EXPLAIN 你的 SELECT 查询
2.当只要一行数据时使用 LIMIT 1
加上 LIMIT 1 可以增加性能。这样一样,MySQL数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据
3.为搜索字段建索引
4.避免 SELECT *
5.垂直分割
6.选择正确的存储引擎
Sql的基本架构
客户端
server端:连接器(连接验证,资源分配),分析器(分析要查的东西是否语法正确),优化器(通过索引选择合适的查找方式),执行器(检查用户权限将结果放入结果集)

redis

一、redis 是什么?都有哪些使用场景?
redis可以说是一种非关系型数据库,与传统的数据库不同的是,redis的数据是存储在内存中的,所以读写速度非常快。
内存存储和持久化:redis支持异步将内存中的数据持久化到硬盘上,同时不影响业务,rdb和aof持久化
海量数据的读写
二、redis都有哪些功能?
1.基于本机内存的缓存功能:频繁访问数据库会造成数据库压力太大,大大损耗性能,使用redis将数据缓存起来,这样下次访问数据是直接冲缓存中读取,效率大大提高。
2.持久化功能。rdb和aof
3.主从复制,提供了监控,提醒以及自动的故障转移的功能,一个Redis服务器可以配备多个备份的服务器。Redis也是利用这两个功能来保证Redis的高可用的
4.集群单台服务器的资源是有限的CPU和IO资源我们可以通过主从复制,主从复制只是做到相同的数据备份,并不能横向扩充内存,单台机器的内存能加大但是始终有上线的,所以我们可以横向扩展,最终每台服务器都负责其中的一部分,这些服务器构成一个整体
三、redis 为什么是单线程的?
因为redis是存内存操作的,内存的IO读写速度是相当快的,redis的核心就是如果数据都存在内存中,那么单线程操作就是最快的,因为多线程的本质就是cpu模拟多线程的本质出现的,多线程操作内存无疑会存在频繁的IO切换,上下文的切换,这样肯定是要浪费时间的,但是单线程就不一样了,他没有上下文的切换就是效率最高的,redis用单个CPU绑定一块内存的数据,这样一个内存的读写操作都是在单个CPU上完成的,所以单线程处理这件事是最高的。
四、什么是缓存穿透?缓存雪崩?怎么解决?
1.缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透
解决方法:布隆过滤器,就是将所有可能存在的数据都hash到一个足够大的map中,一个一定不存在的数据就被拦截掉,这样就可以避免缓存穿透去访问服务器造成服务器的压力
缓存空对象将null也缓存一个值,这样即使不存在的数据也会存在在缓存,避免访问数据库
2.如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。
解决方案:限流
五、怎么保证缓存和数据库数据的一致性?
选择淘汰缓存,数据可能为简单数据或者复杂数据,复杂数据进行缓存的更新操作,成本较高,因为如果一个数据一分钟内更新了二十次,一百次,那么你就要更新缓存一百次二十次,如果删除缓存的话只需要一次就可以,更新缓存并不是简单的更新,假如数据库更新了以后,更新缓存的时候是先查找两个表中的数据是否一致,然后不一致的进行更新。
先更新数据库在淘汰缓存;因为如果先更新数据库在淘汰缓存的话,若缓存淘汰失败那么后面的请求就会得到脏数据,因为缓存和数据库不一致了,先淘汰缓存在更新数据库,就算数据库更新失败,那也就只会产生一次缓存的失败,相比而言后面的对业务影响较小一点
六、redis持久化的两种方式?
1.rdb持久化是指在指定时间间隔内生成数据集的时间点快照,即将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化
redis调用fock()方法,同时拥有父进程和子进,子进程将数据集写到一个临时的RDB文件中,当子进程对新的rdb文件写入完成时,用新的rdb文件替代旧的rdb文件,并且删除掉旧的文件
持久化方式配置:
save 900 1 #900秒时间,至少有一条数据更新,则保存到数据文件中
save 300 10 #300秒时间,至少有10条数据更新,则保存到数据文件中
save 60 10000 #60秒时间,至少有10000条数据更新,则保存到数据文件中
rdb持久化优势:对文件备份比较完美,你可以每小时更新一次近24小时数据或者每天更新一次30天数据
对于灾难恢复比较便捷,可以简单的将一个文件移到其他存储介质上
劣势:因为rdb是通过fork子进程来进行持久化的如果数据较大可能会导致数据停滞几秒钟
如果持久化之前出现宕机,那么此前没有来得及写入磁盘的数据将丢失
2.aof持久化
aof持久化是一种增量的持久化方式,可以在配置文件中配置,然后以追加日志的形式记录在redis的一个.aof文件中
配置:
appendfsync always always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
appendfsync everysec everysec:表示每秒同步一次(折衷,默认值)
appendfsync no no:表示等操作系统进行数据缓存同步到磁盘(快)
优势:Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的
由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容
劣势:丢失一秒钟的数据
rdb在恢复大数据的时候比aof要快
七、redis 如何做内存优化?
1.缩减键值对象,key长度,如在设计键时,在完整的业务情况下,键值越短越好
2.控制key的数量
3.字符串优化
八。redis 淘汰策略有哪些?
1.设置最大内存参数。在redis.windows.config文件中配置可以设置多少个字节,设置我们的最大内存。默认是关闭的
2.内存淘汰策略。redis提供了八中内存置换策略在config配置文件中
(1)volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。

(2)volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰。

(3)volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。

(4)volatile-lfu:从已设置过期时间的数据集挑选使用频率最低的数据淘汰。
淘汰机制的实现:
1.删除失效主键,既然是淘汰那就需要把数据删除,然后保存新的,消极方法就是在主键访问时发现他已经失效那就删除他
积极方法:周期性的探测发现失效就删除
主动删除:当内存超过maxMemory限定时,触发主动清理策略,该策略由启动参数配置决定

zookeeper

一、zookeeper 是什么?
1.zookeeper是一个分布式的协调服务,分布式应用程序可以基于zookeeper实现数据的发布与订阅,分布式协调通知,负载均衡与集群管理
二、.zookeeper 都有哪些功能?
1.统一命名服务
在分布式系统中,客户端能够根据指定名字来获取资源或者服务的地址,提供者等信息
2.集群管理 监控节点存活状态,运行请求
zookeeper能够很容易的实现集群管理的功能,如果有很多server组成一个服务集群,总要有一个leader知道当前权重每台机器的服务状态,一旦有机器不能服务,集群中的其他机器必须知道,同样增加集群的服务能力是增加一台或者多态server必须leader知道
他们的实现方式都是在服务器上创建几个集群节点
3.配置管理
程序总是需要配置的,如果应用程序分散部署在多台机器上,那么要改变配置的话就变得非常困难,现在把这些配置都放在zookeeper的一个节点上,然后相关应用程序对这个节点进行监听,一旦配置发生变化,每个应用程序都会收到通知,然后zookeeper将新的配置信息应用到应用程序就行
三、.zookeeper 有几种部署模式?
单机,集群,伪集群
伪集群的部署方式就是在一台PC中启动多个zookeeper实例
集群部署就是多台服务器上面各单独部署一个zookeeper服务组成一个集群
进入bin目录下9
启动服务:./zkServer.sh start
检查状态: ./zkServer.sh status
Mode:standalone 表明当前是单机模式,也表明部署成功
单机部署方式:
1.服务器上创建工作目录zookeeper,
2.zookeeper下面创建data用于存放节点ID,log下存放相关日志文件
3.解压zookeeper到工作目录下
4.创建zoo.cfg到zookeeper目录下的conf子目录
在zoo.cfg中配置相关文件的参数
tickTime=2000 zookeeper中使用的基本时间单位, 毫秒值
initLimit=10 Follower在启动过程中,会从Leader同步所有最新数据,然后确定自己能够对外服务的起始状态。Leader允许Follower在initLimit时间内完成这个工作
syncLimit=5
dataDir=/home/midware/zookeeper/data 数据目录
dataLogDir=/usr/lib/zookeeper/logs log目录
clientPort=2181 监听client连接的端口号
伪集群部署与集群部署的区别就是在zoo.cfg配置文件中最后面新增下面内容,增加接个server
server.1=127.0.0.1:2888:3888每个
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890
server.服务号=服务地址:服务端口:通信端口
1.本地创建三个虚拟节点,即三个文件夹存放三个不同节点的配置,例如server1/zookeeper,每一个节点下创建data,log文件夹,data下用于存放每一个的节点id,在每个zoo.cfg节点中都增加,server1,server2,server3配置,但是clientPort设置的端口号每个节点不同
2.配置不同节点上的myid,就是在data文件下分别创建存放ID的myid文件,每个myid文件只写上该节点的id
如server1/data/myid 里写1 ,server2/data/myid 里写2
集群部署:跟伪集群部署一样,只不过配置需要变化一下,IP需要变化,端口可以每台机器使用同一个
四、zookeeper 怎么保证主从节点的状态同步?
zookeeper的核心是原子广播,这个机制保证了各个server之间的同步,实现这个机制的协议叫做zab协议
zab协议有两种模式分别是恢复模式或者选主模式和广播模式,当服务启动或者领导者崩溃以后,zab就进入了选主模式,当领导者被选举出来,保证各server和leader之间同步以后,恢复模式就结束了
五、集群中为什么要有主节点?
在分布式环境中,有些业务只需要在集群中的某一台机器中执行,而其他机器可以共享这个结果,这样可以大大减少重复计算,提高性能,所以需要主节点。
六、Zookeeper 和 Dubbo 的关系?
zookeeper作为dubbo的注册中心,也就是将zookeeper的特性引入进来,首先是负载均衡,单注册中心的承载能力是非常有限的,在流量达到一定程度的时候需要分流,分布在多个节点减轻单一系统的压力,所以负载均衡就是这个时候提现出来的,zookeeper配合web应用程序很容易达到负载均衡
二就是资源同步,单单是负载均衡还不够,各个节点之间还需要资源同步,这样zookeeper可以做到,此外zookeeper还管理者服务的注册于发布
七、说一下 zookeeper 的通知机制?
客户端注册监听他关心的目录节点,当目录节点发生变化(数据改变,被删除,子目录节点增加删除)时,zookeeper会通知客户端

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值