最新Java面试题和答案

7 篇文章 2 订阅

Java基础

1. JDK 和 JRE 有什么区别?

JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。
JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。
具体来说 JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。

2. == 和 equals 的区别是什么?
== 解读
对于基本类型和引用类型 == 的作用效果是不同的,如下所示:
基本类型:比较的是值是否相同;
引用类型:比较的是引用是否相同;
代码示例:

String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true

代码解读:因为 x 和 y 指向的是同一个引用,所以 == 也是 true,而 new String()方法则重写开辟了内存空间,所以 == 结果为 false,而 equals 比较的一直是值,所以结果都为 true。

equals 解读
equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。看下面的代码就明白了。
首先来看默认情况下 equals 比较一个有相同值的对象,代码如下:

class Cat {
    public Cat(String name) {
        this.name = name;
    }
 
    private String name;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
}
 
Cat c1 = new Cat("王磊");
Cat c2 = new Cat("王磊");
System.out.println(c1.equals(c2)); // false

输出结果出乎我们的意料,竟然是 false?这是怎么回事,看了 equals 源码就知道了,源码如下:

public boolean equals(Object obj) {
    return (this == obj);
}

原来equals 本质上就是 ==
那问题来了,两个相同值的 String 对象,为什么返回的是 true?代码如下:

String s1 = new String("老王");
String s2 = new String("老王");
System.out.println(s1.equals(s2)); // true

同样的,当我们进入 String 的 equals 方法,找到了答案,代码如下:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

原来是 String 重写了 Object 的 equals 方法,把引用比较改成了值比较。

总结 :== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。

3. 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
不对,两个对象的 hashCode()相同,equals()不一定 true。
代码示例:

String str1 = "通话";
String str2 = "重地";
System.out.println(String.format("str1:%d | str2:%d",  str1.hashCode(),str2.hashCode()));
System.out.println(str1.equals(str2));

执行的结果:

str1:1179395 | str2:1179395
false

代码解读:很显然“通话”和“重地”的 hashCode() 相同,然而 equals() 则为 false,因为在散列表中,hashCode()相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。

4. final 在 java 中有什么作用?

final 修饰的类叫最终类,该类不能被继承。
final 修饰的方法不能被重写。
final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。

5. Java的重载和重写的区别?

  • 重写:父类中定义的方法,在子类中重新实现。
  • 重载:相同方法名称相同,参数类型、参数个数、参数顺序不同。重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载。

6. Java面向对象的三大特征

封装、继承、多态

7. String 属于基础的数据类型吗?

String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而 String 属于对象。

8. java 中操作字符串都有哪些类?它们之间有什么区别?

操作字符串的类有:String、StringBuffer、StringBuilder。
String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。

9. String str="i"与 String str=new String(“i”)一样吗?

不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。

10. 抽象类必须要有抽象方法吗?
不需要,抽象类不一定非要有抽象方法。
示例代码:

abstract class Cat {
    public static void sayHi() {
        System.out.println("hi~");
    }
}

上面代码,抽象类并没有抽象方法但完全可以正常运行。
11. 普通类和抽象类有哪些区别?

普通类不能包含抽象方法,抽象类可以包含抽象方法。
抽象类不能直接实例化,普通类可以直接实例化。

12. 抽象类能使用 final 修饰吗?

不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类,如下图所示,编辑器也会提示错误信息:

13. 接口和抽象类有什么区别?

实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
构造函数:抽象类可以有构造函数;接口不能有。
main 方法:抽象类可以有 main 方法,并且我们能运行它;接口不能有 main 方法。
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。

14. java 中 IO 流分为几种?

按功能来分:输入流(input)、输出流(output)。
按类型来分:字节流和字符流。
字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。

15. BIO、NIO、AIO 有什么区别?

BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。


集合

1. 常用的集合类型有哪些?这些集合的区别?
在这里插入图片描述
在这里插入图片描述

答:常用集合类型:List、Set、Map、Stack、Queue。
区别:1. List、Set、Stack和Queue是存储单列数据的集合,Map是存储键值对的双列数据的集合;
List、Set和Queue集合是实现的Collection接口,Stack是继承的Vector,Map是单独实现的一个接口。
List中存储的数据是有顺序的,并且值允许重复;Map中存储的数据是无序的,它的键是不允许重复的,但是值是允许重复的;Set中存储的数据是无顺序的,并且不允许重复。

2. 集合中常用的实现类?

  • List:
    1. Vector:数组数据结构,对数组的操作都加上了synchronized,线程安全。增删,查询都很慢。
    2. ArrayList:数组数据结构,扩容是1.5倍,线程不安全,替代Vector,查询速度快,增删速度慢。
    3. LinkedList:双向链表结构,可以使用二分查找,线程不安全,增删速度快,查询速度慢。
  • Set:
    1. HashSet:使用HashMap的key进行存储,所以不允许重复。运行为null。通过hash算法,排列顺序和插入顺序无关。
    2. LinkedHashSet:使用HashMap的key进行存储,用链表实现,排列顺序就是插入顺序。
    3. TreeSet:使用NavigableMap的key进行存储,底层使用红黑树进行排序。
  • Map:
    1. HashMap:jdk1.7底层使用数组+单链表的形式存储数据,而jdk1.8是用数组+单链表+红黑树存储数据。线程不安全。两倍扩容。无序,key不允许重复,key和value允许为null。
    2. Hahtable:数组+单链表实现。线程安全。两倍+1扩容。无序,key不允许重复。key和value都不允许为null。
    3. ConcurrentHashMap:存储方式和HashMap一样。通过把整个Map分为N个Segment,通过用ReentrantLock重入锁对写操作的segmet加锁,来保证线程安全,但是效率提升N倍,默认提升16倍。
    4. TreeMap:可以指定比较器(comparator)排序的Map集合,按集合的key排序,key不允许重复。
    5. WeakHashMap:弱引用的Map集合,清除集合中不再使用的内容,使用gc进行回收:WeakHashMap的键是“弱键”。在 WeakHashMap 中,当某个键不再正常使用时,会被从WeakHashMap中被自动移除,并把key值放入ReferenceQueue中。
    6. IndentityHashMap:key可以重复的Map集合:比较键(和值)时使用引用相等性代替对象相等性,也就是说使用 == 而不是使用 equals。
  • Queue
    1.PriorityQueue:数组实现。取出的顺序并不是加入队列的顺序,而是按元素节点大小排序后的顺序。
    2.ArrayDeque:数组实现的双端队列。
    3.BlockingQueue:阻塞队列,注意它是在java.util.concurrent包下。
  • Stack:继承Vector类的栈对象。

LinkedList为什么是使用双向链表?
因为单链表只有一个指向直接后继节点的指针,查找只能从头开始遍历,双向链表有两个指针,分别指向前继和后继,所以可以使用二分查找进行查询节点,查找效率比较高。

3. Jdk1.8中HashMap中链表长度超过多少个节点会转成红黑树?为什么是这个节点数量,而不设置成更大或更小?
链表元素个数大于等于8会转成红黑树,链表元素个数小于等于6时,树结构还原成链表,以达到提高查询效率。
原因:
1.我们知道链表的时间复杂度是O(n),红黑树的时间复杂度O(logn),很明显红黑树复杂度比链表复杂度低,至于为什么不之间使用红黑树是因为树节点所占空间是普通节点的两倍,而且节点数量小于8时,它们之间的查找效率相差并不大。
2.至于为什么是8,源码上说,为了配合使用分布良好的hashCode,树节点很少使用。并且在理想状态下,受随机分布的hashCode影响,链表中的节点遵循泊松分布,而且根据统计,链表中节点数是8的概率已经接近千分之一,而且此时链表的性能已经很差了。所以在这种比较罕见和极端的情况下,才会把链表转变为红黑树。
4. HashMap的实现原理?
1.首先从构造函数说起,HashMap有两个主要的构造函数,当new 一个对象时传入初始化容量的时候会进行初始化工作,如果使用无参构造函数则就把负载因子设为初始值如下:

//定义初始化容量的,会进行数组和一些参数的初始化
public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
//无参构造函数,则什么也不会做
public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }
 //真正的初始化构造函数
 public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }
  1. 当put一个元素的时候,首先会调用hash(Object key),计算key的hash值。
static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
  1. 然后调用putVal()方法。首先判断定义的数组是否为null或者长度是否为零,如果是就会调用resize()方法进行数据扩容,来完成数组的初始化工作。
  2. 通过(表长度-1)与hash值((length - 1) & hash)计算key在数组的下标,如果在该下标的数组值为空,则直接new一个节点存入数组。
  3. 如果不为空,判断这个位置元素的key是否与加入的key相等,如果一样只进行值更新。
  4. 如果不相等,判断这个位置的元素是不是红黑树节点,如果是就调用putTreeVal()函数进行添加元素。
  5. 如果不是红黑树节点,说明是一个单向链表,则通过循环将节点加入到链表表尾,并判断节点长度大于等于8时,把链表转成红黑树。
  6. 最后会根据判断大于阈值时,进行调用resize()函数进行扩容。
  7. 在resize()扩容后会根据以前节点的hash值重新计算下标位置。

5. HashMap中hash(Object key),为什么(hashcode >>> 16)
首先hashcode >>> 16是取hash值的高16位
由于和(length-1)运算,length 绝大多数情况小于2的16次方。所以始终是hashcode 的低16位(甚至更低)参与运算。要是高16位也参与运算,会让得到的下标更加散列
所以这样高16位是用不到的,如何让高16也参与运算呢。所以才有hash(Object key)方法。让他的hashCode()和自己的高16位^运算。所以(h >>> 16)得到他的高16位与hashCode()进行^运算。
6.Jdk1.7中的HashMap有什么问题?
就是在hashMap在多线程情况下put节点,达到Resize条件,使用的头插法会产上节点循环引用的问题,当调用Get方法获取节点数据的时候会进行死循环。Jdk1.8采用了尾插法解决了这一问题。但是jdk1.7和jdk1.8都没解决节点丢失的问题。
7.怎么使多线程下集合线程安全?
10. 使用线程安全的集合,比如vector、HashTable、ConcurrentHashMap、CountDownLatch、Cyclicbarrier等。
11. 使用Colletions.synchronized方法使集合同步。

8.ConcurrentHashMap的实现原理?
JDK1.7实现:数组+链表
JDK1.7保证并发安全:Segment + HashEntry + ReentrantLock
JDK1.8实现:数组+链表+红黑树
JDK1.8保证并发安全:Node + CAS + synchronized
https://blog.csdn.net/ddxd0406/article/details/81389583
详细点击链接

线程

1. 并行和并发有什么区别?

并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群。
所以并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。

2. 线程和进程的区别?

进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程。进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源,减少切换次数,从而效率更高。线程是进程的一个实体,是cpu调度和分派的基本单位,是比程序更小的能独立运行的基本单位。同一进程中的多个线程之间可以并发执行。

3. 线程池都有哪些状态?这些状态之间的关系?
在这里插入图片描述

4. 创建线程有哪几种方式?

①. 继承Thread类创建线程类
定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
创建Thread子类的实例,即创建了线程对象。
调用线程对象的start()方法来启动该线程。
②. 通过Runnable接口创建线程类
定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
调用线程对象的start()方法来启动该线程。
③. 通过Callable和Future创建线程
创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
使用FutureTask对象作为Thread对象的target创建并启动新线程。
调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

8. 创建线程池有哪几种方式?

Java通过Executors(jdk1.5并发包)提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

所有线程池相关问题

5. Runnable 和 Callable 有什么区别?

1.Runnable的线程执行代码在run()方法中,Callable的线程执行代码在call()方法中。
2.run()方法不可以抛出异常,call()方法可以抛出异常。
3.Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。

6. sleep() 和 wait() 有什么区别?

sleep()和wait()都是线程暂停执行的方法。
1、这两个方法来自不同的类分别是Thread和Object,sleep方法属于Thread类中的静态方法,wait属于Object的成员方法。
2、sleep()是线程类(Thread)的方法,不涉及线程通信,调用时会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,用于线程间的通信,调用时会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才进入对象锁定池准备获得对象锁进入运行状态。
3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围)。
4、sleep()方法必须捕获异常InterruptedException,而wait()\notify()以及notifyAll()不需要捕获异常.
**注意**
  sleep方法只让出了CPU,而并不会释放同步资源锁。
  线程执行sleep()方法后会转入阻塞状态。
  sleep()方法指定的时间为线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行。
  notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度。

7. Thread的join()和yield()的区别?

join()方法使调用该方法的线程在此(或之前)执行完毕,也就是等待调用join()的线程执行完run()方法后再往下继续执行。注意该方法也需要捕捉异常。就是说让该线程在执行完RUN()方法以后再执行join方法后面的代码,就是说可以让两个线程合并起来,用于实现同步功能。
yield()该方法与sleep() 类似 只不过不能够由用户指定暂停多长的时间,并且调用yield()方法的对象线程会直接进入就绪状态,只能让同优先级的线程有执行的机会。 前面提到了 sleep不会释放锁标识yield也不会释放锁标识。

9. 如果线程池的任务队列满了,该怎么处理提交的任务?

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务
ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务

需要注意的是:线程池默认的拒绝策略是AbortPolicy
10. 线程池中 submit()和 execute()方法有什么区别?

1.接收的参数不一样:submit(Callable task)、submit(Runnable task, T result)、submit(Runnable task)归属于ExecutorService接口。execute(Runnable command)归属于Executor接口。ExecutorService继承了Executor。
2.submit有返回值,而execute没有。
3.submit方便Exception处理。

11. ThreadLocal是什么?

ThreadLocal提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的变量是对应的互相独立的。通过get和set方法就可以得到当前线程对应的值。
做个不恰当的比喻,从表面上看ThreadLocal相当于维护了一个map,key就是当前的线程,value就是需要存储的对象。
这里的这个比喻是不恰当的,实际上是ThreadLocal的静态内部类ThreadLocalMap为每个Thread都维护了一个数组table,ThreadLocal确定了一个数组下标,而这个下标就是value存储的对应位置。

详解点击链接

ThreadLocal中一个子线程获取父线程中的ThreadLocal的值
点击查看详情

同步

1. synchronized 底层实现原理?

详解点击链接

volatile的底层实现原理
点击查看详情
超深入讲解----这个

ReentrantLock的实现原理
点击查看详情

7. AQS是什么?
AQS是一个抽象类AbstractQueuedSynchronizer(抽象队列同步器)。它是基于等待队列用来实现同步锁(ReentrantLock,Semaphore,CountdownLatch,CyclicBarrier,Exchanger等等)核心组件的基础框架,它本身没有实现任何的同步接口,只是定义了获取以及释放同步状态的方法来提供自定义的同步组件。
详解点击链接

CountDownLatch和CyclicBarrier的实现原理
点击查看详情

2. synchronized 和 volatile 的区别是什么?

1.volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
2.volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
3.volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
4.volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
5.volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。

详解点击链接

3. synchronized 和 Lock 有什么区别?

首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可);
Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

4. synchronized 和 ReentrantLock 区别是什么?

synchronized是和if、else、for、while一样的关键字,ReentrantLock是类,这是二者的本质区别。既然ReentrantLock是类,那么它就提供了比synchronized更多更灵活的特性,可以被继承、可以有方法、可以有各种各样的类变量,ReentrantLock比synchronized的扩展性体现在几点上:
ReentrantLock可以对获取锁的等待时间进行设置,这样就避免了死锁
ReentrantLock可以获取各种锁的信息
ReentrantLock可以灵活地实现多路通知
另外,二者的锁机制其实也是不一样的:ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操作的应该是对象头中mark word。

5. 锁的类型都有哪些?
详情点击链接
6. 说一下CAS,及CAS有什么问题?

CAS,是Java保证原子性的一种重要方法,也是一种乐观锁的实现方式。
它需要先提前一步获取旧值,然后进入此方法比较当下的值是否与旧值相同,如果相同,则更新数据,否则退出方法,重复一遍刚才的动作。由此可见,CAS方法是非堵塞的。CAS方法需要三个参数,变量内存值、旧的预期值、数据更新值;
问题:
1、ABA问题,比如刚开始读取到备份是3,然后被其他线程连续修改两次,最终结果还是3,那么CAS很可能识别不到数据发生了改变,这种情况对程序造成了极大的安全隐患。可以通过添加版本号等标志位来解决该问题。
2、循环时间长开销大,如果长时间自旋不成功,会给CPU带来很大开销。可以使用自适应自旋锁解决这个问题
3、只能保证一个共享变量的原子操作。比如AtomicInteger都是每次只能对一个变量进行原子性控制。

8. 分布式锁实现的方式?

详解点击链接

9. 说一下 atomic 的原理?

Atomic包中的类基本的特性就是在多线程环境下,当有多个线程同时对单个(包括基本类型及引用类型)变量进行操作时,具有排他性,即当多个线程同时对该变量的值进行更新时,仅有一个线程能成功,而未成功的线程可以向自旋锁一样,继续尝试,一直等到执行成功。
Atomic系列的类中的核心方法都会调用unsafe类中的几个本地方法。我们需要先知道一个东西就是Unsafe类,全名为:sun.misc.Unsafe,这个类包含了大量的对C代码的操作,包括很多直接内存分配以及原子操作的调用,而它之所以标记为非安全的,是告诉你这个里面大量的方法调用都会存在安全隐患,需要小心使用,否则会导致严重的后果,例如在通过unsafe分配内存的时候,如果自己指定某些区域可能会导致一些类似C++一样的指针越界到其他进程的问题。

10. LongAdder的原理,和AtomicLong的区别?

LongAdder是jdk1.8新提供的一个原子类,想要了解它的原理首先要先知道Striped64,因为LongAdder就是根据他来实现的,Striped64是一个支持并发的累加器,可以在高并发下支持多线程的累加操作。原理就是内部定义了一个volatile的 base属性,用来在低并发下cas的使用UnSafe进行计数,在高并发下会使用内部定义的Cell内部类,并提供一个volatile的cell[]数组,高并发下cas修改base属性值会失败,让后根据线程的hashcode计算出来cell数据的下标,如果为null就新创建一个,非空就cas的修改值。最后获取值的时候就对base和cell数组求和。
区别:在低并发下其实他们区别并不大,组要体现在高并发下,AtomicLong会一直cas去修改值,会消耗大量的cpu资源。

详解点击


类加载

1. 讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当 new 的时候, 他们的执行顺序。
此题考察的是类加载器实例化时进行的操作步骤(加载–>连接->初始化)。

父类静态代变量、
父类静态代码块、
子类静态变量、
子类静态代码块、
父类非静态变量(父类实例成员变量)、
父类构造函数、
子类非静态变量(子类实例成员变量)、
子类构造函数。

2. 类加载的流程,类加载器都有哪些?它们之间的关系和负责加载的内容?

详解点击链接

3. 类加载机制有哪些?

  • 全盘负责委托机制:当一个ClassLoader加载一个类时,除非显示的使用另一个ClassLoader,否则该类所依赖和引用的类也都由这个ClassLoader加载。
  • 双亲委派机制:指先委托父类加载器寻找目标类,在找不到的情况下再在自己的路径中查找并载入目标类。

如果自己定义一个String,会被加载到吗?为什么?
首先不会加载到,原因:点击查看详情

类加载器是什么?使用场景?
虚拟机把描述类的数据从class字节码文件加载到内存,并对数据进行检验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
点击查看详情


反射

怎么理解Java反射?
简单的来说,反射机制其实就是指程序在运行的时候能够获取自身的信息。如果知道一个类的名称或者它的一个实例对象, 就能把这个类的所有方法和变量的信息(方法名,变量名,方法,修饰符,类型,方法参数等等所有信息)找出来。如果明确知道这个类里的某个方法名+参数个数 类型,还能通过传递参数来运行那个类里的那个方法,这就是反射。

怎么获取一个私有方法的对象

Class clazz = Class.forName(“包名.类名”);
Method method = clazz.getDeclaredMethod(“方法名”, int.class);


JVM

JVM内存结构和JMM
JVM内存结构和内存模型

垃圾回收
垃圾回收

JVM常问面试题

怎么排查oom?
可以借助Jvisualvm工具把堆栈、线程等信息dump下来,进行分析。
如果服务器出现oom怎么排查?
点击查看


JavaWeb

1. jsp的内置对象。

  • pageContext:JSP的页面容器
  • request : 获取用户的请求信息
  • response: 服务器向客户端的回应信息
  • session :用来保存每一个用户的信息
  • application:表示所有用户的共享信息
  • config : 服务器配置信息,可以取得初始化参数
  • out : 用于向客户端、浏览器输出数据。
  • page:指向了当前jsp程序本身。
  • exception:封装了jsp程序执行过程中发生的异常和错误信息。

2. 四种属性范围:

  • page(pageContext):只在一个页面中保存属性。 跳转之后无效;
  • request:只在一次请求中有效,服务器跳转之后有效。 客户端跳无效;
  • session:再一次会话中有效。服务器跳转、客户端跳转都有效。 网页关闭重新打开无效;
  • application:在整个服务器上保存,所有用户都可使用。 重启服务器后无效;

3. session 和 cookie 有什么区别?

由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session.典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书。这个Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比如Memcached之类的来放 Session。
思考一下服务端如何识别特定的客户?这个时候Cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。有人问,如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。
Cookie其实还可以用在一些方便用户的场景下,设想你某次登陆过一个网站,下次登录的时候不想再次输入账号了,怎么办?这个信息可以写到Cookie里面,访问网站的时候,网站页面的脚本可以读取这个信息,就自动帮你把用户名给填了,能够方便一下用户。这也是Cookie名称的由来,给用户的一点甜头。所以,总结一下:Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。

4. 说一下 session 的工作原理?

其实session是一个存在服务器上的类似于一个散列表格的文件。里面存有我们需要的信息,在我们需要用的时候可以从里面取出来。类似于一个大号的map吧,里面的键存储的是用户的sessionid,用户向服务器发送请求的时候会带上这个sessionid。这时就可以从中取出对应的值了。

5. 如果客户端禁止 cookie 能实现 session 还能用吗?

Cookie与 Session,一般认为是两个独立的东西,Session采用的是在服务器端保持状态的方案,而Cookie采用的是在客户端保持状态的方案。但为什么禁用Cookie就不能得到Session呢?因为Session是用Session ID来确定当前对话所对应的服务器Session,而Session ID是通过Cookie来传递的,禁用Cookie相当于失去了Session ID,也就得不到Session了。
假定用户关闭Cookie的情况下使用Session,其实现途径有以下几种:
1.设置php.ini配置文件中的“session.use_trans_sid = 1”,或者编译时打开打开了“–enable-trans-sid”选项,让PHP自动跨页传递Session ID。
2.手动通过URL传值、隐藏表单传递Session ID。
3.用文件、数据库等形式保存Session ID,在跨页过程中手动调用。

6.forward 和 redirect 的区别?

Forward和Redirect代表了两种请求转发方式:直接转发和间接转发。
直接转发方式(Forward),客户端和浏览器只发出一次请求,Servlet、HTML、JSP或其它信息资源,由第二个信息资源响应该请求,在请求对象request中,保存的对象对于每个信息资源是共享的。
间接转发方式(Redirect)实际是两次HTTP请求,服务器端在响应第一次请求的时候,让浏览器再向另外一个URL发出请求,从而达到转发的目的。
举个通俗的例子:
直接转发就相当于:“A找B借钱,B说没有,B去找C借,借到借不到都会把消息传递给A”;
间接转发就相当于:“A找B借钱,B说没有,让A去找C借”。

tcp协议连接和断开的过程?

7. 简述 tcp 和 udp的区别?

TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。
TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。
Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。
TCP对系统资源要求较多,UDP对系统资源要求较少。

8. tcp 为什么要三次握手,两次不行吗?为什么?

为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤。
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认。

9. 说一下 tcp 粘包是怎么产生的?

①. 发送方产生粘包在这里插入图片描述
采用TCP协议传输数据的客户端与服务器经常是保持一个长连接的状态(一次连接发一次数据不存在粘包),双方在连接不断开的情况下,可以一直传输数据;但当发送的数据包过于的小时,那么TCP协议默认的会启用Nagle算法,将这些较小的数据包进行合并发送(缓冲区数据发送是一个堆压的过程);这个合并过程就是在发送缓冲区中进行的,也就是说数据发送出来它已经是粘包的状态了。
②. 接收方产生粘包在这里插入图片描述
接收方采用TCP协议接收数据时的过程是这样的:数据到底接收方,从网络模型的下方传递至传输层,传输层的TCP协议处理是将其放置接收缓冲区,然后由应用层来主动获取(C语言用recv、read等函数);这时会出现一个问题,就是我们在程序中调用的读取数据函数不能及时的把缓冲区中的数据拿出来,而下一个数据又到来并有一部分放入的缓冲区末尾,等我们读取数据时就是一个粘包。(放数据的速度 > 应用层拿数据速度)

10. OSI 的七层模型都有哪些?

应用层:网络服务与最终用户的一个接口。
表示层:数据的表示、安全、压缩。
会话层:建立、管理、终止会话。
传输层:定义传输数据的协议端口号,以及流控和差错校验。
网络层:进行逻辑地址寻址,实现不同网络之间的路径选择。
数据链路层:建立逻辑连接、进行硬件地址寻址、差错校验等功能。
物理层:建立、维护、断开物理连接。

11. get 和 post 请求有哪些区别?

GET在浏览器回退时是无害的,而POST会再次提交请求。
GET产生的URL地址可以被Bookmark,而POST不可以。
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST么有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET参数通过URL传递,POST放在Request body中。

13.说一下 JSONP 实现原理?

jsonp 即 json+padding,动态创建script标签,利用script标签的src属性可以获取任何域下的js脚本,通过这个特性(也可以说漏洞),服务器端不在返货json格式,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。


设计模式

超详细的设计模式


框架

1. springmvc的工作流程?

可以看这个博客:
详情点击链接
https://www.cnblogs.com/jiyukai/p/7629498.html

2. springmvc的常用注解

  • @Controller:用于控制层注解 , (特殊的@Component)。
  • @RestContoller:用户控制器注解,等于@Controller+@ResponseBody.
  • @RequestMappint:用于方法上,来映射 Request 请求与处理器。参数:
    1. value:定义request请求的映射地址
    2. method:定义地request址请求的方式,包括【GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.】默认接受get请求,如果请求方式和定义的方式不一样则请求无法成功。
    3. params:定义request请求中必须包含的参数值。
    4. headers:定义request请求中必须包含某些指定的请求头,如:RequestMapping(value = “/something”, headers = “content-type=text/*”)说明请求中必须要包含"text/html", "text/plain"这中类型的Content-type头,才是一个匹配的请求。
    5. consumes:定义请求提交内容的类型。
    6. produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回
  • @ResponseBody:将返回值内容通过springMVC提供的HttpMessageConverter接口转换为json、xml等格式的数据,再转换为java对象绑定到Controller类方法的参数上,即将返回值放在response体内。
  • @RequestBody:允许request的参数在request体中,而不是在直接链接在地址后面。此注解放在参数前。
  • @PathVariable:用来接收路径参数,如/news/001,可接收001作为参数,此注解放置在参数前。
  • @RequestParam:value:请求参数名,require:是否必须存在,默认为true,defaultValue:默认值,表示如果请求中没有同名参数时的默认值;处理简单类型的绑定,作用在参数前。
  • @ModelAttribute:用于把参数保存到model中,可以注解方法或参数,注解在方法上的时候,该方法将在处理器方法执行之前执行,然后把返回的对象存放在 session或模型属性中。
  • @ControllerAdvice 使一个Controller成为全局的异常处理类, 类中用ExceptinHandler方法注解的方法可以处理所有Controller发生的异常。
  • @ExceptionHandler: 注解到方法上, 出现异常时会执行该方法。

3. spring的优点?

  1. 非侵入式设计:Spring是一种非侵入式(non-invasive)框架,它可以使应用程序代码对框架的依赖最小化。
  2. 方便解耦、简化开发:Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护工作都交给Spring容器的管理,大大的降低了组件之间的耦合性。
  3. 支持AOP:Spring提供了对AOP的支持,它允许将一些通用任务,如安全、事物、日志等进行集中式处理,从而提高了程序的复用性。
  4. 支持声明式事务处理:只需要通过配置就可以完成对事物的管理,而无须手动编程。
  5. 方便程序的测试:Spring提供了对Junit4的支持,可以通过注解方便的测试Spring程序。
  6. 方便集成各种优秀框架:Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如Struts、Hibernate、MyBatis、Quartz等)的直接支持。
  7. 降低Jave EE API的使用难度:Spring对Java EE开发中非常难用的一些API(如JDBC、JavaMail等),都提供了封装,使这些API应用难度大大降低。
  8. IOC反转控制(也可以叫DI依赖注入)
    就是对象依赖关系不用你来维护,由IOC容器来维护(对象间依赖关系就是类与类之间的依赖关系,使用与被使用。之前这些要你自己去完成它们的依赖关系,有了IOC容器这工作就就交给IOC容器来完成。)
  9. AOP面向切面编程

4. 说下Spring的Aop
AOP即 Aspect Oriented Program 面向切面编程,是对OOP即面向对象的程序设计和POP面向过程的程序设计的补充。
首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。

所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务
所谓的周边功能,比如性能统计,日志,事务管理等等

周边功能在 Spring 的面向切面编程AOP思想里,即被定义为切面
在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发,然后把切面功能和核心业务功能 “编织” 在一起,这就叫AOP
详情点击链接
5. Spring 的IOC
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象的创建和销毁等交给容器控制,而不是传统的在你的对象内部直接控制。
DI—Dependency Injection,即“依赖注入”,是IOC的一种实现方式,即是一种技术:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。
这样设计的目的:把对象的创建和依赖交给Spring的IOC容器管理,实现对象之间的“解耦”。
Spring中Bean的生命周期?

在这里插入图片描述

Spring Bean的生命周期

spring bean的创建方式

springbean的装配机制

Spring中通过@Autowired等标签注入Bean的过程?
通俗说法
点击查看详情

Spring中如何解决循环依赖的?
详细点击链接
6. Spring中使用了哪些设计模式?都在什么地方使用的?
详情点击链接
7. Spring中bean的作用域有哪几种?

  1. singleton:单例模式,IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。
  2. prototype : 原型模式,每次请求都会创建一个新的 bean 实例。
  3. request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
  4. session : 每一次HTTP请求都会产生一个新的 bean,同一个Session共享一个Bean实例。不同Session使用不同的实例。
  5. global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。

8. spring中bean的线程安全问题
spring中bean的线程安全问题
9. Spring事务的传播特性和隔离级别
Spring事务的传播特性和隔离级别
Spring的多事物?

Spring的事务运行机制?

10. Springboot常用的配置文件有哪些?

说下Springboot的优点?
1.独立运行spring容器:Springboot提供了一个启动类,只要运行该类的main()方法,就能启动web容器(因为Springboot内置了tomcat和jetty等web容器),在部署项目时,不需要再打压成war包,只要打压成jar包,利用java-jar xx.jar命令就能启动。
2.简化依赖:Spring 提供了很多常用的的 starter pom 来简化 Maven 的依赖加载。
3.自动配置:Spring Boot 会根据在类路径中的 jar 包、类,为 jar 包里的类自动配置 Bean,这样会极大地减少我们要使用的配置。
4.无代码生成和 xml 配置:Spring Boot中使用Java 配置和注解配置组合,来完成Spring的配置,不需要再去配置 xml文件。
10. Mybatis和Hibernate的区别

  1. Mybatis和Hibernate都可以成为ORM框架,但是Mybatis是半ORM的,HIbernate是全ORM,因为Hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。
  2. MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是那种缓存。
  3. Hibernate是重量级的框架, 里面封装比较完整,功能比较丰富,比如sql优化、关系映射和日志记录等等都会消耗大量资源。MyBatis是轻量级的框架, 学习使用门槛低, 使用灵活方便,只做了字段方面的映射,手动优化sql等等。

11.Mybatis的缓存机制
有实现原理
mybatis的缓存机制

sqlSession是干什么的?


数据库

UNION是干什么的?
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
请注意,UNION 内部的每个 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每个 SELECT 语句中的列的顺序必须相同。
UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。

1. sql的连接类型
1、自关联(join或inner join)
2、左外关联(left join或left outer join)
3、右外关联(right join或right outer join)
4、全关联(full join)
2. where和having的区别

where执行在返回结果之前,且先于聚合函数之前,用于过滤行,不能使用聚合函数;having执行在返回结果之后,可以使用聚合查询,对返回的结果进行过滤。

4. sql的约束

  • NOT NULL:非空约束。
  • UNIQUE:唯一约束,此字段的每条记录必须唯一,一般我们用来约束id,他和primary key一样,都对字段保证了唯一性。
  • PRIMARY KEY:主键约束。设置此字段为这张表的主键,每个表应该有一个主键,而且每个表都只能有一个主键,主键字段必须唯一且不能有null值
  • FOREIGN KEY:外建约束。
  • CHECK:约束用于限制字段中的值的范围。
  • DEFAULT:缺省约束:默认值,如果定义了默认值,再插入数据时如果没有插入数据,会根据默认值插入

5. 事务的四大特征
ACID,原子性(Atomicity)、一致性(Correspondence)、隔离
性(Isolation)、持久性(Durability)。

(1)原子性:整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
(2)一致性:在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
(3)隔离性:隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行 相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆, 必须串行化或序列化请 求,使得在同一时间仅有一个请求用于同一数据。
(4)持久性:在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
Mysql查询的执行过程?
在这里插入图片描述
6. sql调优
点击查看详情

7. mysql的四种隔离级别?怎么实现的?
Mysql的四个隔离级别是如何实现的

知道事物的MVCC吗?
多版本并发控制
https://blog.csdn.net/qq_38538733/article/details/88902979

8. Oracle也是使用Limit进行分页的吗?
Oracle是使用的rownum和between来进行分页的。rownum是虚拟列,是得出结果后,再进行计算的。所以,只能是小于的,无法大于,要使用的大于,就必须使用别名。rownum的效率比between高。原因点击查看详情
9. Mysql索引的类型?
点击链接查看详情

主键索引和普通索引有什么区别?
主键索引也叫聚集索引,非主键索引也叫二级索引和非聚集索引,主键索引的叶子节点存放的是整行数据,主键索引的叶子节点存放的是主键的值。主键索引效率要比非主键索引高,因为避免了回表操作。

唯一索引和普通索引的区别?
超详细
点击链接描述
如果一个查询不走索引怎么办?为什么会出现不走索引这种情况?
force index(),这个指令可以指定本次查询强制使用哪个索引,因为Mysql优化器的选择并不一定是最优的索引。
ignore index(),这个指令可以强制Mysql在查询时,不使用某索引。
怎么重新刷新下索引?
mysql优化Analyze Table
10. Mysql索引的实现算法?为什么使用该算法?
点击查看详情
11. 数据库的锁?表级锁、页级锁、行级锁
点击查看详情
行级锁实现算法

order算法

12.MySQL的存储引擎MyISAM和InnoDB的区别

  • 数据存储方式:
    MYIsam:非聚簇,.frm表的结构信息,.MYD表的数据,.MYI表的索引
    Innodb:聚簇,.frm表的结构信息,.idb表的数据和索引在一起
  • 索引中叶子节点:MyIsam的叶子节点中是指向MYD文件中的数据地址,InnoDB的叶子节点直接指向数据。所以Innodb必须设置主键。避免了回表。
  • 事物:MyISAM不支持事务,而InnoDB支持。InnoDB的AUTOCOMMIT默认是打开的,即每条SQL语句会默认被封装成一个事务,自动提交,这样会影响速度,所以最好是把多条SQL语句显示放在begin和commit之间,组成一个事务去提交。
  • 锁方式:InnoDB支持数据行锁定,MyISAM不支持行锁定,只支持锁定整个表。即 MyISAM同一个表上的读锁和写锁是互斥的,MyISAM并发读写时如果等待队列中既有读请求又有写请求,默认写请求的优先级高,即使读请求先到,所以 MyISAM不适合于有大量查询和修改并存的情况,那样查询进程会长时间阻塞。因为MyISAM是锁表,所以某项读操作比较耗时会使其他写进程饿死。
  • InnoDB的主键范围更大,最大是MyISAM的2倍。
  • InnoDB不支持全文索引,而MyISAM支持。全文索引是指对char、 varchar和text中的每个词(停用词除外)建立倒排序索引。MyISAM的全文索引其实没啥用,因为它不支持中文分词,必须由使用者分词后加入空 格再写到数据表里,而且少于4个汉字的词会和停用词一样被忽略掉。

13.mysql的索引的数据结构?
MYsql使用的是Hash和B+树
其它适合索引的数据结构:二叉树、红黑树、hash、b树、b+树(mysql默认)
二叉树当数据单边增长是(比如从1…100增长),树的深度会一直加深,每次查询都会进行多次磁盘IO,虽然红黑树中书的结构有所减轻,但是在大数据量是依然会很满,hash虽然查询很快,但是没办法做范围内查找,所以在索引中作为配合B+树做范围内查询的快速定位。b树,采用节点的横向扩展,解决了树的深度过高的问题,比之前的二叉树和红黑树效率高了很多。但是因为考虑到磁盘IO比较慢,而且节点中保存索引对应的数据,所以每次磁盘IO获取到的索引数据不多。为了解决在满足一次磁盘IO也就是页大小中尽可能的获取多的索引数据,所以采用b+树,在非叶子节点只保存索引,不保存数据,只有在叶子节点中保存数据。而且叶子节点采用指针连接,提高范围内查找的效率。
14.mysql调优的覆盖索引,回表
MySQL中的回表查询,我的理解是二级索引无法直接查询所有列的数据,所以通过二级索引查询到聚簇索引后,再查询到想要的数据,这种通过二级索引查询出来的过程,就叫做回表。

如果explain查看执行计划,在Extra中如果出现using index condition就是二级索引回表,是否表示是通过回表查询到的数据

count(1)和count(),为什么使用count()更好
点击查看详情

redo log、bin log、undo log 的作用和区别?
添加链接描述
预写日志

15.mysql的分库分表
可以使用mycat

mysql的主从复制
添加链接描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值