• Java面试题


    Docker+springBoot+Dubbo+Zookeeper+mybatis+redis+rabbitmq+quartz+graphql+kotlin+elasticsearch+JWT+shiro+AOP+flyway+DataX+dblink
    封装类/包装类Wrapper

    1.构造器不能被继承,因此不能被重写,但可以被重载。

    2.如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;如果两个对象的hashCode相同,它们并不一定相同;

    3.JVM加载class文件的原理机制

    加载/验证/准备/解析/初始化

    类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader的子类)

    双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成

    类加载器-运行时数据区-执行引擎-垃圾回收机制

     4.内存泄漏

    理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题

    然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生关闭(close)或清空(flush)

    5.栈(先进后出(FILO)

    6.是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?
    答:不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在调用静态方法时可能对象并没有被初始化。

    7.String s = new String("xyz");创建了几个字符串对象?
    答:两个对象,一个是静态区的"xyz",一个是用new创建在堆上的对象。

    8.Java 中的final关键字有哪些用法?
    答:(1)修饰类:表示该类不能被继承;(2)修饰方法:表示方法不能被重写;(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。

    9.类加载顺序

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

    先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构造器。 

    10.List、Set、Map是否继承自Collection接口?

    答:List、Set 是,Map 不是。Map是键值对映射容器,与List和Set有明显的区别,而Set存储的零散的元素且不允许有重复元素(数学中的集合也是如此),List是线性结构的容器,适用于按数值索引访问元素的情形。

    Collection是一个接口,它是Set、List等容器的父接口

    11.List、Map、Set三个接口存取元素时,各有什么特点

    List以特定索引来存取元素,可以有重复元素。

    Set不能存放重复元素

    Map保存键值对(key-value pair)映射,映射关系可以是一对一或多对一

    ArrayList是基于索引的数据接口,它的底层是数组,它可以以O(1)时间复杂度对元素进行随机访问

    LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。 

    相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引

    LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素

    LinkedList和ArrayList是另个不同变量列表的实现。ArrayList的优势在于动态的增长数组,非常适合初始时总长度未知的情况下使用。LinkedList的优势在于在中间位置插入和删除操作,速度是最快的。

     LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。

    ArrayList实现了可变大小的数组。它允许所有元素,包括null。 每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。

    LinkedHashMap则记录了插入顺序

    TreeMap默认升序

    12.请说出与线程同步以及线程调度相关的方法

    execute 无返回值
            ExecutorService service = Executors.newFixedThreadPool(100);
            for(int i = 1; i <= 100; i++) {
                service.execute(new AddMoneyThread(account, 1));
            }
            service.shutdown();
            while(!service.isTerminated()) {}
            System.out.println("账户余额: " + account.getBalance());

    submit有返回值
            List<Future<Integer>> list = new ArrayList<>();

    ExecutorService service = Executors.newFixedThreadPool(10);
            for(int i = 0; i < 10; i++) {
                list.add(service.submit(new MyTask((int) (Math.random() * 100))));
            }
    
            int sum = 0;
            for(Future<Integer> future : list) {
                // while(!future.isDone()) ;
                sum += future.get();
            }
    
            System.out.println(sum);

    13.什么是线程池
    答:先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销
    14.简述synchronized 和java.util.concurrent.locks.Lock&ReentrantLock的区别
     答:Lock是Java 5以后引入的新的API,和关键字synchronized相比
    主要相同点:Lock 能完成synchronized所实现的所有功能;
    主要不同点:Lock有比synchronized更精确的线程语义和更好的性能,而且不强制性的要求一定要获得锁。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且最好在finally 块中释放(这是释放外部资源的最好的地方)。
    synchronized是和if、else、for、while一样的关键字&ReentrantLock是类
    ReentrantLock可以对获取锁的等待时间进行设置,这样就避免了死锁
    ReentrantLock可以获取各种锁的信息
    ReentrantLock可以灵活地实现多路通知

            ReentrantLock是Lock的默认实现,在聊ReentranLock之前,我们需要先弄清楚一些概念:

    1. 可重入锁:可重入锁是指同一个线程可以多次获得同一把锁;ReentrantLock和关键字Synchronized都是可重入锁

    2. 可中断锁:可中断锁时只线程在获取锁的过程中,是否可以相应线程中断操作。synchronized是不可中断的,ReentrantLock是可中断的

    3. 公平锁和非公平锁:公平锁是指多个线程尝试获取同一把锁的时候,获取锁的顺序按照线程到达的先后顺序获取,而不是随机插队的方式获取。synchronized是非公平锁,而ReentrantLock是两种都可以实现,不过默认是非公平锁

    4. Object中wait类似的方法Condition相同




    15.数据库事务的ACID是指什么
    原子性/一致性/隔离性/持久性
    default 可重复读 不可避免幻读 --事务A读取了符合条件的行,发现插入了事务B插入的数据

    脏读

    A事务读取B事务尚未提交的数据并在此基础上操作,而B事务执行回滚,那么A读取到的数据就是脏数据。

    不可重复读

    事务A重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务B修改过了。

    幻读

    事务A重新执行一个查询,返回一系列符合查询条件的行,发现其中插入了被事务B提交的行

    16.获得一个类的类对象有哪些方式

    方法1:类型.class,例如:String.class

    方法2:对象.getClass(),例如:"hello".getClass()

    方法3:Class.forName(),例如:Class.forName("java.lang.String")

     17.如何通过反射创建对象

    方法1:通过类对象调用newInstance()方法,例如:String.class.newInstance()

    方法2:通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:String.class.getConstructor(String.class).newInstance("Hello");

    18.如何通过反射调用对象的方法
    String str = "hello";
    Method m = str.getClass().getMethod("toUpperCase");
    System.out.println(m.invoke(str));
    19.常用设计模式
    共23种设计模式,包括:Abstract Factory(抽象工厂模式),Builder(建造者模式),Factory Method(工厂方法模式),Prototype(原始模型模式),Singleton(单例模式);Facade(门面模式),Adapter(适配器模式),Bridge(桥梁模式),Composite(合成模式),Decorator(装饰模式),Flyweight(享元模式),Proxy(代理模式);Command(命令模式),Interpreter(解释器模式),Visitor(访问者模式),Iterator(迭代子模式),Mediator(调停者模式),Memento(备忘录模式),Observer(观察者模式),State(状态模式),Strategy(策略模式),Template Method(模板方法模式), Chain Of Responsibility(责任链模式)
    20.用Java写一个单例类
    饿汉
    private static Singleton instance = new Singleton();
    public static Singleton getInstance(){
    return instance;
    }
    懒汉
    private static Singleton instance = null;
    private Singleton() {}
    public static synchronized Singleton getInstance(){
    if (instance == null) instance = new Singleton();
    return instance;
    }
    21.Servlet
    它通过多线程方式运行其service()方法,一个实例可以服务于多个请求,并且其实例一般不会销毁
    Servlet接口中有哪些方法
    Web容器加载Servlet并将其实例化后,Servlet生命周期开始,容器运行其init()方法进行Servlet的初始化;请求到达时调用Servlet的service()方法,service()方法会根据需要调用与请求对应的doGet或doPost等方法;当服务器关闭或项目被卸载时服务器会将Servlet实例销毁,此时会调用Servlet的destroy()方法。
    22.状态码问题
    3XX系列:

    代表需要客户端采取进一步的操作才能完成请求,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的 Location 域中指明。这系列中最常见的有301、302状态码。

    301-- Moved Permanently 被请求的资源已永久移动到新位置 永久重定向
    302--临时重定向

    4XX系列:

    表示请求错误。代表了客户端看起来可能发生了错误,妨碍了服务器的处理。常见有:401、404状态码。

    5xx系列:

    代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。常见有500、503状态码。

    22.转发(forward)和重定向(redirect)的区别

    从一个网站redirect到其他网站

    forward是容器中控制权的转向,是服务器请求资源

    23.什么是Web Service(Web服务)

    Web Service就是一个应用程序,它向外界暴露出一个能够通过Web进行调用的API

    之所以称之为Web Service(SOA),是因为它基于HTTP协议传输数据,这使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件,就可相互交换数据或集成。

    24.Session&SessionFactory

    Session是一个轻量级非线程安全的对象(线程间不能共享session)

    SessionFactory对应Hibernate的一个数据存储的概念,它是线程安全的,可以被多个线程并发访问

    可以使用ThreadLocal将session和当前线程绑定在一起,这样可以让同一个线程获得的总是同一个session

    25.Hibernate的悲观锁和乐观锁机制

    乐观锁:顾名思义,对并发事务持乐观态度(认为对数据的并发操作不会经常性的发生)(版本字段version)

    当然,更通用的方式,可以使用版本号来实现CAS乐观锁:

    UPDATE t_yue SET money=$new_money,ver=$ver_new 
    WHERE uid=$uid AND 
    ver=$ver_old;

    悲观锁:顾名思义悲观的认为在数据处理过程中极有可能存在修改数据的并发事务(包括本系统的其他事务或来自外部系统的事务)

    26.MyBatis中使用#和$书写占位符有什么区别

    # 占位符

    $ 字符替换

    27.MyBatis中的动态SQL是什么意思

    主要有:- if- choose / when / otherwise- trim- where- set- foreach

    28.什么是IoC和DI?DI是如何实现的?

    IoC:控制反转是把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理

    所谓的"控制反转"就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系

    DI:应用组件不应该负责查找资源或者其他依赖的协作对象
    依赖注入可以通过setter方法注入(设值注入)、构造器注入和接口注入三种方式来实现,Spring支持setter注入和构造器注入,通常使用构造器注入来注入必须的依赖关系,对于可选的依赖关系,则setter注入是更好的选择,setter注入需要类提供无参构造器或者无参的静态工厂方法来创建对象。
    29.缓存雪崩/缓存预热/缓存穿透
    30.什么是XSS攻击?什么是SQL注入攻击?什么是CSRF攻击?
    XSS(Cross Site Script,跨站脚本攻击)
    CSRF攻击(Cross Site Request Forgery,跨站请求伪造)
    SQL注入攻击是注入攻击最常见的形式
    31.多线程
    创建线程的方式
    继承Thread类
    实现Runnable接口
    Callable+Future/FutureTask
    32.CyclicBarrier&CountDownLatch区别
    CyclicBarrier的某个线程运行到某个点上之后,该线程即停止运行,直到所有的线程都到达了这个点,所有线程才重新运行
    CyclicBarrier只能唤起一个任务,CountDownLatch可以唤起多个任务
    CyclicBarrier可重用,CountDownLatch不可重用,计数值为0该CountDownLatch就不可再用了 
    CountDownLatch则不是,某线程运行到某个点上之后,只是给某个数值-1而已,该线程继续运行
     
    CountDownLatch

    假如有这样一个需求,当我们需要解析一个Excel里多个sheet的数据时,可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要统计解析总耗时。分析一下:解析每个sheet耗时可能不一样,总耗时就是最长耗时的那个操作。

    CountDownLatch称之为闭锁,它可以使一个或一批线程在闭锁上等待,等到其他线程执行完相应操作后,闭锁打开,这些等待的线程才可以继续执行。确切的说,闭锁在内部维护了一个倒计数器。通过该计数器的值来决定闭锁的状态,从而决定是否允许等待的线程继续执行。

    1. 创建CountDownLatch对象

    2. 调用其实例方法 await(),让当前线程等待

    3. 调用 countDown()方法,让计数器减1

    4. 当计数器变为0的时候, await()方法会返回

    https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648933134&idx=1&sn=65c2b9982bb6935c54ff33082f9c111f&chksm=88621b30bf159226d41607292a1dc83186f8928744dbc44acfda381266fa2cdc006177b44095&token=773938509&lang=zh_CN#rd

     CyclicBarrier 

    公司组织旅游,大家都有经历过,10个人,中午到饭点了,需要等到10个人都到了才能开饭,先到的人坐那等着

    吃饭完毕之后,所有人都去车上,待所有人都到车上之后,驱车去下一景点玩

    CyclicBarrier通常称为循环屏障。它和CountDownLatch很相似,都可以使线程先等待然后再执行。不过CountDownLatch是使一批线程等待另一批线程执行完后再执行

    调用await()的时候,当前线程将会被阻塞,需要等待其他员工都到达await了才能继续 cyclicBarrier.await();

    https://www.cnblogs.com/itsoku123/p/11242165.html

    Semaphore常用场景:限流

    有5个空位,门口有个门卫,手中5把钥匙分别对应5个车位上面的锁,来一辆车,门卫会给司机一把钥匙,然后进去找到对应的车位停下来,出去的时候司机将钥匙归还给门卫。停车场生意比较好,同时来了100两车,门卫手中只有5把钥匙,同时只能放5辆车进入,其他车只能等待,等有人将钥匙归还给门卫之后,才能让其他车辆进入

    33.volatile关键字的作用
    多线程主要围绕可见性和原子性两个特性而展开,使用volatile关键字修饰的变量,保证了其在多线程之间的可见性,即每次读取到volatile变量,一定是最新的数据
    使用volatile则会对禁止语义重排序,当然这也一定程度上降低了代码执行效率
    volatile的一个重要作用就是和CAS结合,保证了原子性,详细的可以参见java.util.concurrent.atomic包下的类,比如AtomicInteger。
    34.什么是线程安全

    如果你的代码在多线程下执行和在单线程下执行永远都能获得一样的结果,那么你的代码就是线程安全的。 

    不可变

    像String、Integer、Long这些,都是final类型的类,任何一个线程都改变不了它们的值,要改变除非新创建一个,因此这些不可变对象不需要任何同步手段就可以直接在多线程环境下使用

    绝对线程安全

    不管运行时环境如何,调用者都不需要额外的同步措施。要做到这一点通常需要付出许多额外的代价,Java中标注自己是线程安全的类,实际上绝大多数都不是线程安全的,不过绝对线程安全的类,Java中也有,比方说CopyOnWriteArrayList、CopyOnWriteArraySet

     相对线程安全

    相对线程安全也就是我们通常意义上所说的线程安全,像Vector这种,add、remove方法都是原子操作,不会被打断,但也仅限于此,如果有个线程在遍历某个Vector、有个线程同时在add这个Vector,99%的情况下都会出现ConcurrentModificationException,也就是fail-fast机制。

     线程非安全

    这个就没什么好说的了,ArrayList、LinkedList、HashMap等都是线程非安全的类

    35.Java中如何获取到线程dump文件

    死循环、死锁、阻塞、页面打开慢等问题,打线程dump是最好的解决问题的途径。所谓线程dump也就是线程堆栈,获取到线程堆栈有两步:

     (1)获取到线程的pid,可以通过使用jps命令,在Linux环境下还可以使用ps -ef | grep java

    (2)打印线程堆栈,可以通过使用jstack pid命令,在Linux环境下还可以使用kill -3 pid

    36.如何在两个线程之间共享数据

    通过在线程之间共享对象就可以了,然后通过wait/notify/notifyAll、await/signal/signalAll进行唤起和等待,比方说阻塞队列BlockingQueue(有界阻塞队列&无界阻塞队列)就是为线程之间共享数据而设计的

    37.sleep方法和wait方法有什么区别 

    sleep方法和wait方法都可以用来放弃CPU一定的时间,

    不同点在于如果线程持有某个对象的监视器,

    sleep方法不会放弃这个对象的监视器,

    wait方法会放弃这个对象的监视器

    38.生产者消费者模型的作用是什么(消息队列 rabbitMq等)

    提升整个系统的运行效率&解耦

    39.ThreadLocal有什么用

    简单说ThreadLocal就是一种以空间换时间的做法,在每个Thread里面维护了一个以开地址法实现的ThreadLocal.ThreadLocalMap,把数据进行隔离,数据不共享,自然就没有线程安全方面的问题了

    40.ConcurrentHashMap的并发度是什么

    ConcurrentHashMap的并发度就是segment的大小,默认为16,这意味着最多同时可以有16条线程操作

    hashMap是线程不安全的,HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,采用哈希表来存储的

    HashMap 基于 hashing 原理,我们通过 put ()和 get ()方法储存和获取对象。当我们将键值对传递给 put ()方法时,它调用键对象的 hashCode ()方法来计算 hashcode,让后找到 bucket 位置来储存值对象。当获取对象时,通过键对象的 equals ()方法找到正确的键值对,然后返回值对象。HashMap 使用 LinkedList 来解决碰撞问题,当发生碰撞了,对象将会储存在 LinkedList 的下一个节点中。 HashMap 在每个 LinkedList 节点中储存键值对对象。

    45.ReadWriteLock是什么

    首先明确一下,不是说ReentrantLock不好,只是ReentrantLock某些时候有局限。

    如果使用ReentrantLock,可能本身是为了防止线程A在写数据、线程B在读数据造成的数据不一致,

    但这样,如果线程C在读数据、线程D也在读数据,读数据是不会改变数据的,没有必要加锁,但是还是加锁了,降低了程序的性能。

    ReadWriteLock是一个读写锁接口,ReentrantReadWriteLock是ReadWriteLock接口的一个具体实现,

    实现了读写的分离,读锁是共享的,写锁是独占的,读和读之间不会互斥,读和写、写和读、写和写之间才会互斥,提升了读写的性能。

    46.Linux环境下如何查找哪个线程使用CPU最长

    (1)获取项目的pid,jps或者ps -ef | grep java,这个前面有讲过

    (2)top -H -p pid,顺序不能改变

    47.HashMap原理

     48.nio和 bio &aio的区别是啥

     IO是面向流的,NIO是面向缓冲区的, AIO 异步IO ,BIO阻塞IO

    NIO和IO最大的区别:IO是以流的方式处理数据,而NIO是以块的方式处理数据;IO对事件的处理是阻塞的,NIO是非阻塞的

    NIO的核心部分:

    • Channel
    • Buffer
    • Selector

    NIO主要分为标准输入输出和网络请求

    50.代理

    Jdk cglib jdk底层是利用反射机制,需要基于接口方式,这是由于 
    Proxy.newProxyInstance(target.getClass().getClassLoader(), 
    target.getClass().getInterfaces(), this); 
    Cglib则是基于asm框架,实现了无反射机制进行代理,利用空间来换取了时间,代理效率高于jdk 

    51.JVM内存模型

    内存屏障:为了保障执行顺序和可见性的一条cpu指令 
    重排序:为了提高性能,编译器和处理器会对执行进行重拍 
    happen-before:操作间执行的顺序关系。有些操作先发生。 
    主内存:共享变量存储的区域即是主内存 
    工作内存:每个线程copy的本地内存,存储了该线程以读/写共享变量的副本  

    线程独占

    • 栈(存储局部变量表、操作栈、动态链接、方法出口等信息)
    • 本地方法栈(native方法)
    • 程序计数器

    线程共享

    • 堆(堆所有线程共享,分代管理)
    • 方法区(类信息、常量、静态变量,jdk1.7中的永久代和jdk1.8中的metaspace都是方法区的一种实现)

     
    • 我们定义的所有变量都储存在 主内存

    • 每个线程都有自己 独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝)

    • 线程对共享变量所有的操作都必须在自己的工作内存中进行,不能直接从主内存中读写(不能越级)

    • 不同线程之间也无法直接访问其他线程的工作内存中的变量,线程间变量值的传递需要通过主内存来进行。(同级不能相互访问)

    52.什么情况会造成内存泄漏

    1. 这些对象是可达的,即在有向图中,存在通路可以与其相连;

    2. 这些对象是无用的,即程序以后不会再使用这些对象。

    如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。

    53.产生死锁必须具备以下四个条件

    • 互斥条件:该资源任意一个时刻只由一个线程占用。

    • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

    • 不剥夺条件:线程已获得的资源在末使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。

    • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

    54.三次握手和四次挥手

     

    质量保证

    • Checkstyle
    • FindBugs
    • SonarQube

    压测

    • JMeter
    • JMH
    • AB
    • LoadRunner

     55.java中==和equals和hashCode的区别

      基本数据类型:也称原始数据类型。byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值。

    引用数据类型: 当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。

    如果两个对象根据equals()方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。
    如果两个对象根据equals()方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定要产生相同的整数结果

     56.Iterator和ListIterator的区别

     ListIterator有add()方法,可以向List中添加对象,而Iterator不能。

    ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。

    ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。

    都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改

    57.一个Http请求

    DNS域名解析 –> 发起TCP的三次握手 –> 建立TCP连接后发起http请求 –> 服务器响应http请求,浏览器得到html代码 –> 浏览器解析html代码,并请求html代码中的资源(如javascript、css、图片等) –> 浏览器对页面进行渲染呈现给用户

    58.MyISAM与InnoDB的区别是什么?

    1、 存储结构

    MyISAM:每个MyISAM在磁盘上存储成三个文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm文件存储表定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名是.MYI (MYIndex)。
    InnoDB:所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。

    2、 存储空间

    MyISAM:可被压缩,存储空间较小。支持三种不同的存储格式:静态表(默认,但是注意数据末尾不能有空格,会被去掉)、动态表、压缩表。
    InnoDB:需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。

    3、 可移植性、备份及恢复

    MyISAM:数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作。
    InnoDB:免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了。

    4、 事务支持

    MyISAM:强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持。
    InnoDB:提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。

    5、 AUTO_INCREMENT

    MyISAM:可以和其他字段一起建立联合索引。引擎的自动增长列必须是索引,如果是组合索引,自动增长可以不是第一列,他可以根据前面几列进行排序后递增。
    InnoDB:InnoDB中必须包含只有该字段的索引。引擎的自动增长列必须是索引,如果是组合索引也必须是组合索引的第一列。

    6、 表锁差异

    MyISAM:只支持表级锁,用户在操作myisam表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。
    InnoDB:支持事务和行级锁,是innodb的最大特色。行锁大幅度提高了多用户并发操作的新能。但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。

    7、 全文索引

    MyISAM:支持 FULLTEXT类型的全文索引
    InnoDB:不支持FULLTEXT类型的全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好。

    8、 表主键

    MyISAM:允许没有任何索引和主键的表存在,索引都是保存行的地址。
    InnoDB:如果没有设定主键或者非空唯一索引,就会自动生成一个6字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值。

    9、 表的具体行数

    MyISAM:保存有表的总行数,如果select count(*) from table;会直接取出出该值。
    InnoDB:没有保存表的总行数,如果使用select count(*) from table;就会遍历整个表,消耗相当大,但是在加了wehre条件后,myisam和innodb处理的方式都一样。

    10、 CURD操作

    MyISAM:如果执行大量的SELECT,MyISAM是更好的选择。
    InnoDB:如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。DELETE 从性能上InnoDB更优,但DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除,在innodb上如果要清空保存有大量数据的表,最好使用truncate table这个命令。

    11、 外键

    MyISAM:不支持
    InnoDB:支持
    通过上述的分析,基本上可以考虑使用InnoDB来替代MyISAM引擎了,原因是InnoDB自身很多良好的特点,比如事务支持、存储 过程、视图、行级锁定等等,在并发很多的情况下,相信InnoDB的表现肯定要比MyISAM强很多。另外,任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。如果不是很复杂的Web应用,非关键应用,还是可以继续考虑MyISAM的,这个具体情况可以自己斟酌。

    59.Java只有值传递,没有引用传递!
    一种是按值传递,一种是引用传递!
    引用传递:传递的是指向值的地址的指针
     
    • 值传递
    方法调用时,实参的数值被复制到另一个变量,然后传递复制的副本。
     
    • 引用传递
    方法调用时,实际参数的地址直接传递到方法中。
    60.MySQL中myisam与innodb的区别,至少5点
    InnoDB是基于索引来完成行锁
     
    • 1>.InnoDB支持事物,而MyISAM不支持事物
    • 2>.InnoDB支持行级锁,而MyISAM支持表级锁
    • 3>.InnoDB支持MVCC, 而MyISAM不支持
    • 4>.InnoDB支持外键,而MyISAM不支持
    • 5>.InnoDB不支持全文索引,而MyISAM支持。

     

    缓存穿透
    试想一下,如果有黑客会对你的系统进行攻击,拿一个不存在的id 去查询数据,会产生大量的请求到数据库去查询。可能会导致你的数据库由于压力过大而宕掉。
    之所以会发生穿透,就是因为缓存中没有存储这些空数据的key。从而导致每次查询都到数据库去了。
    别忘了设置过期时间。
    2.3.2 BloomFilter
    BloomFilter 类似于一个hbase set 用来判断某个元素(key)是否存在于某个集合中。
    这种方式在大数据场景应用比较多,比如 Hbase 中使用它去判断数据是否在磁盘上。还有在爬虫场景判断url 是否已经被爬取过。
    这种方案可以加在第一种方案中,在缓存之前在加一层 BloomFilter ,在查询的时候先去 BloomFilter 去查询 key 是否存在,如果不存在就直接返回,存在再走查缓存 -> 查 DB。
     
    缓存击穿
    在平常高并发的系统中,大量的请求同时查询一个 key 时,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去。这种现象我们称为缓存击穿。
    上面的现象是多个线程同时去查询数据库的这条数据,那么我们可以在第一个查询数据的请求上使用一个 互斥锁来锁住它。
     
    缓存雪崩
    缓存雪崩的情况是说,当某一时刻发生大规模的缓存失效的情况,比如你的缓存服务宕机了,会有大量的请求进来直接打到DB上面。结果就是DB 称不住,挂掉。
     
     
    使用集群缓存,保证缓存服务的高可用
    这种方案就是在发生雪崩前对缓存集群实现高可用,如果是使用 Redis,可以使用 主从+哨兵 ,Redis Cluster 来避免 Redis 全盘崩溃的情况。
     
    Spring -> Spring Boot > Spring Cloud 这样的关系。
    前端或二方 - > ng集群 -> zuul集群 -> eureka-server集群 -> service
    Spring Cloud Zuul路由是微服务架构的不可或缺的一部分,提供动态路由,监控,弹性,安全等的边缘服务。Zuul是Netflix出品的一个基于JVM路由和服务端的负载均衡器。

    explain select * from project where id='1a49e54f856541e9848f7653c719e60f'
     
    60、Redis是单进程单线程的?
    答:Redis是单进程单线程的,redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。
     
    60.1乐观锁

    同一个用户并发扣款时,有一定概率出现数据不一致,可以使用CAS乐观锁的方式,在不降低吞吐量,保证数据的一致性:

    UPDATE t_yue SET money=$new_money

    WHERE uid=$uid AND money=$old_money;

     

    byName : 设置为 byName ,那么在创建该对象时,会根据该对象的 set 方法到容器中查找是否有对应的标识符对象存在,如果存在则注入该对象。 

    项目优化 : 
    面向服务分布式架构SOA:
    拆分架构 :
    1.分担服务器压力。
    2.提高项目并发能力。
    拆分原则 :
    1.根据业务和职能拆分。
    为了减轻数据库压力,提高数据库效率?
    解决方案 :
    1.集群(主主,主备,读写分离)
    2.分表,分库。
    3.开启缓存。
    4.开启索引.
    5.sql语句优化。
    6.数据库设计优化。
    数据库本身优化,还可以加redis缓存?
    1.减轻数据库压力(查询缓存,不再查询数据库)。
    2.提高查询效率(redis是内存版nosql数据库)
    3.提高并发能力。
    dubbo : 服务治理中间件(分布式服务架构)
    特点 : 
    1.rpc 远程通信
    2.NIO new IO 异步通信。

    dubbo优化 :
    1.服务集群。
    2.序列化优化 kryo
    3.失败重试。

    第一级优化 : 
    1.集群(主主,主备,读写分离)
    作用 :
    高可用和高并发。
    2.分表和分库(大数据查询效率低)
    3.开启缓存
    4.开启索引
    5.优化sql查询
    5.数据库设计

    第二级优化 :redis缓存 
    作用 :
    1.减轻数据库压力
    2.提高项目查询效率
    (redis是一个nosql版内存版数据库)
    redis服务器本身优化:
    1.内存淘汰策略。
    2.线程安全问题。
    3.redis3.0 : 自动高可用,自动容错。

    第三极优化 : solr进行搜索
    作用 :
    1.减轻数据库压力。
    2.提高检索效率(搜索索引)
    案例 : 
    solr服务器本身优化:
    1.集群(高可用,高容错)

    第四级优化 :SOA面向服务分布式的架构
    作用 : 
    1.分担服务器压力。
    2.提高项目并发能力。 jvm优化。
    优化 : soa使用dubbo+zookeeper tomcat服务器优化
    dubbo优化 :
    1.服务集群。
    2.序列化优化 kryo
    3.失败重试。

    第五级优化 : fastDFS分布式文件系统

    作用 : 存储图片
    1.访问效率高。
    2.自动容错。
    3.线性扩容。

    第六级优化 : 使用mq消息服务器,应用于服务与服务之间进行通信。
    作用 : 1.异步通信。2.任务异步处理。优势:流量削峰。
    优化mq : 集群。

    第七级优化 : 页面静态化。
    1.查询效率提高(访问静态数据)
    2.并发能力提高。
    技术 : freemarket实现静态化。
    思考 : 优化。
    缺点 : 
    html页面商品数据。
    商品描述,规格,详情。
    不能及时和数据库同步。
    优化 : 
    mq进行同步静态页面。
    同步流程:
    商品添加,修改,删除。
    发送消息
    详情系统接收消息动态生成,删除html页面。

    第8级优化 : nginx的使用。
    1.http服务器。
    2.负载均衡。
    优化:
    集群。
    页面静态化 : 
    技术选型 ; freemarket
    优势 : 简单,容易上手,语法简单,功能更强大。

    mysql中的索引 :
    mysql中普遍使用B+Tree做索引,但在实现上又根据聚簇索引和非聚簇索引而不同。
    聚簇索引 : 
    所谓聚簇索引,就是指主索引文件和数据文件为同一份文件,聚簇索引主要用在Innodb存储引擎中。在该索引实现方式中B+Tree的叶子节点上的data就是数据本身,
    key为主键,如果是一般索引的话,data便会指向对应的主索引,如下图所以:

    在B+Tree的每个叶子结点增加一个指向相邻叶子节点的指针,就形成了带有顺序访问指针的B+Tree.做这个优化的目的是为了提高区间访问的性能,例如图4中
    如果要查询key为18到49的所有数据记录,当找到18后,只需顺着节点和指针顺序遍历就可以一次性访问到所有数据节点,极大提高了区间查询效率。

    非聚餐索引 :
    非聚餐索引就是指B+Tree的叶子节点上的data,并不是数据本身,而是数据存放的地址。主索引和辅助索引没啥区别,只是主索引中的key一定的是唯一的。主要
    用在MyISAM存储引擎中,如下图 :  

    非聚簇索引比聚簇索引多了一次读取数据的IO操作,所以查找性能上会差。

    61.MyISAM索引与InnoDB索引相比较 : 

    MyISAM支持全文索引(FULLTEXT)、压缩索引,InnoDB不支持;
    InnoDB支持事务,MyISAM不支持;
    MyISAM顺序存储数据,索引叶子节点保存对应数据行地址,辅助索引和主键索引相差无几;InnoDB主键节点同时保存数据行,其他辅助索引保存的是主键索引的值;
    MyISAM键值分离,索引载入内存(key_buffer_size),数据缓存依赖操作系统;InnoDB键值一起保存,索引与数据一起载入InnoDB缓存池;MyISAM主键(唯一)索引
    按升序来存储,InnoDB则不一定;
    MyIASM索引的基数值(Cardinality,show index 命令可以看见)是精确的,InnoDB则是估计值。这里涉及到信息统计的知识,MyISAM统计信息是保存磁盘中,在alter
    表或Analyze table操作更新此信息,而InnoDB则是在表第一次打开的时候估计值保存在缓存区内;
    MyISAM处理字符串索引时用增量保存的方式,如第一个索引是‘preform’,第二个是‘preformence’,则第二个保存时'7,ance',这个明显的好处是缩短索引,但是缺陷就是不支持
    倒序提取索引,必须顺序遍历获取索引。

    为什么选用B+/-Tree
    一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗,
    相对于内存存取,I/O存储的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度。
    换句话说,索引的结构组织要尽力减少查找过程中磁盘I/O的存取次数。

    B-Tree : 如果一次检索需要访问4个节点,数据库系统设计者利用磁盘预读原理,把节点的大小设计为一个页,那读取一个节点只需要一次I/O操作,完成这次
    检索操作,最多需要3次I/O(根节点常驻内存)。数据记录越小,每个节点存放的数据就越多,树的高度也就越小,I/O操作就少了,检索效率也就上去了。
    B+Tree : 非叶子节点只存Key,大大的减少了非叶子节点的大小,那么每个节点就可以存放更多的记录,树更矮了,I/O操作更少了。所以B+Tree拥有更好的性能。

    62.幂等性 内存划分,threadLocal,多线程和线程池,local,syncal,map,map里面的排序,hashmap,hashtable,分布式和分布式锁的

    解决线程安全问题,本质上就是解决资源共享问题,一般有以下手段:

    1)可重入(不依赖环境);2)互斥(同一时间段只允许一个线程使用);3)原子操作;4)Thread-Local

    63.阿里巴巴的消息队列 : 
    RocketMQ是一个纯java、分布式、队列模型的开源消息中间件,前身是Metaq
    RocketMQ是一款分布式、队列模型的消息中间件,具有以下特点 : 
    1.能够保证严格的消息顺序。
    2.提高丰富的消息拉取模式。
    3.高效的订阅者水平扩展能力。
    4.实时的消息订阅机制。
    5.亿级消息堆积能力。

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

    final 修饰的类叫最终类,该类不能被继承。

    final 修饰的方法不能被重写。

    final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。

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

    BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。

    NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。

    AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

    65. String 类的常用方法都有那些?

    • indexOf():返回指定字符的索引。

    • charAt():返回指定索引处的字符。

    • replace():字符串替换。

    • trim():去除字符串两端空白。

    • split():分割字符串,返回一个分割后的字符串数组。

    • getBytes():返回字符串的 byte 类型数组。

    • length():返回字符串长度。

    • toLowerCase():将字符串转成小写字母。

    • toUpperCase():将字符串转成大写字符。

    • substring():截取字符串。

    • equals():字符串比较。

    66. String str="i"与 String str=new String("i")一样吗?

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

    67.如何获取自动生成的(主)键值?

    <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
    <selectKey keyProperty="id" order="AFTER" resultType="int">
    select LAST_INSERT_ID()
    </selectKey>
    INSERT INTO USER(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address})
    </insert>

    68.通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?

    Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略

    Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。

    69.Mybatis是如何进行分页的?分页插件的原理是什么?

    Mybatis是如何进行分页的?分页插件的原理是什么?

    Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

    分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

    举例:select * from student,拦截sql后重写为:select t.* from (select * from student)t limit 0,10

    70. ArrayList和LinkList各自的特点和区别?

    1、ArrayList和LinkedList可想从名字分析,它们一个是Array(动态数组)的数据结构,一个是Link(链表)的数据结构,此外,它们两个都是对List接口的实现。前者是数组队列,相当于动态数组;后者为双向链表结构,也可当作堆栈、队列、双端队列

    2、当随机访问List时(get和set操作),ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。

    3、当对数据进行增加和删除的操作时(add和remove操作),LinkedList比ArrayList的效率更高,因为ArrayList是数组,所以在其中进行增删操作时,会对操作点之后所有数据的下标索引造成影响,需要进行数据的移动。

    4、从利用效率来看,ArrayList自由性较低,因为它需要手动的设置固定大小的容量,但是它的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;而LinkedList自由性较高,能够动态的随数据量的变化而变化,但是它不便于使用。

    5、ArrayList主要控件开销在于需要在lList列表预留一定空间;而LinkList主要控件开销在于需要存储结点信息以及结点指针信息。

    Arraylist:

    优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。

    缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。

    LinkedList:

    优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景

    缺点:因为LinkedList要移动指针,所以查询操作性能比较低。

    HashMap的实现机制:

    1. 维护一个每个元素是一个链表的数组,而且链表中的每个节点是一个Entry[]键值对的数据结构。
    2. 实现了数组+链表的特性,查找快,插入删除也快。
    3. 对于每个key,他对应的数组索引下标是 int i = hash(key.hashcode)&(len-1);
    4. 每个新加入的节点放在链表首,然后该新加入的节点指向原链表首

    71.存储引擎的 InnoDB 与 MyISAM

    1)InnoDB支持事务,MyISAM不支持,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了。

    2)MyISAM适合查询以及插入为主的应用,InnoDB适合频繁修改以及涉及到安全性较高的应用

    3)InnoDB支持外键,MyISAM不支持

    4)从MySQL5.5.5以后,InnoDB是默认引擎

    5)InnoDB不支持FULLTEXT类型的索引

    6)InnoDB中不保存表的行数,如select count() from table时,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含where条件时MyISAM也需要扫描整个表

    7)对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引

    8)清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表

    9)InnoDB支持行锁(某些情况下还是锁整表,如 update table set a=1 where user like ‘%lee%’



    https://www.jianshu.com/p/088a9d0b8249
  • 相关阅读:
    图解设计模式-Visitor模式
    图解设计模式-Decorator模式
    图解设计模式-Strategy模式
    图解设计模式-Bridge模式
    HashMap源码
    LinkedList源码
    Vector源码
    ArrayList源码
    图解设计模式-Abstract Factory模式
    图解设计模式-Builder模式
  • 原文地址:https://www.cnblogs.com/ywsheng/p/11237589.html
Copyright © 2020-2023  润新知