java 基础面试题及答案。持续更新

问题来源

  1. JDK 和 JRE 有什么区别?
    1. jdk是Java开发包,jre是Java运行环境
  2. == 和 equals 的区别是什么?
    1. == 比较的是地址,equals比较的是内容
  3. 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
    1. hashCode() 和 equals() 都是可以重写的。返回完全自己定义。但是开规范上来讲,最好一致。
    2. (规范上)重写equals()方法必须重写hashCode()方法,以保证内容相同的对象hashCode()一致。
    3. (规范上)两个对象用equals()比较返回true,那么两个对象的hashCode()方法必须返回相同的结果
  4. final 在 java 中有什么作用?
    1. 修饰属性:用来声明常量,表示属性不能被更改
    2. 修饰方法:表示方法不能被重写
    3. 修饰类: 表示类不能被继承
  5. “a” 和 new String(“a”)有什么不同?
    1. "a"存在于常量池, new String(“a”) 存在于堆区中
  6. 堆栈区的区别
    1. 堆:被所有线程共享,存放对象本身,不存放基本类型。
    2. 栈:每个线程(每个方法)包含一个栈空间。存放基础类型,和对象的引用(对象在堆空间的地址)。
    3. 方法区: 跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
  7. String 属于基础的数据类型吗?
    1. 不属于
  8. java 中操作字符串都有哪些类?它们之间有什么区别?
    1. String, StringBuffer, StringBuilder
    2. StringBuffer里面的操作方法大多是同步的(使用synchronized修饰),保证了线程安全
    3. StringBuilder 不保证线程安全,StringBuffer 和 StringBuilder里有append、delete, reverse()(反转)等修改字符串的方法
  9. 如何将字符串反转?
    1. 空格分组遍历,或者利用 StringBuffer和StringBuilder的reverse方法
        String str = new String("123456789");
        String[] strArr = str.split("");
        String newStr = "";
        for (int i = strArr.length; i > 0; i--) {
            newStr += strArr[i - 1];
        }
        System.out.println(newStr);

        // 或者
        StringBuffer str1 = new StringBuffer("123456789");
        StringBuffer newStr1 = str1.reverse();
        StringBuilder str2 = new StringBuilder("123456789");
        StringBuilder newStr2 = str2.reverse();
        System.out.println(newStr1);
        System.out.println(newStr2);
  1. String 类的常用方法都有那些?
    1. split: 分割数组
    2. indexOf: 查找参数字符串在字符串中出现的位置,没有返回-1
    3. replace和replaceAll: 替换
    4. getBytes:转换字节
    5. equals: 字符串比较
    6. substring:字符串截取
    7. isEmpty: null验证
    8. endsWith: 是否已指定字符结尾
    9. startsWith: 是否已指定字符开始
    10. concat: 字符串合并(拼接)
        String str = new String("123456789123");
        System.out.println(str);
        // 分割数组
        String[] strArr = str.split("");
        System.out.println("分割数组:" + Arrays.toString(strArr));

        // 查找参数字符串在字符串中出现的位置,没有返回-1
        int position = str.indexOf("3");
        System.out.println("出现的位置:" + position);

        // 替换
        String newStr = str.replace("1","xx");
        String newStr2 = str.replaceAll("1","xx");
        System.out.println("替换:" + newStr);
        System.out.println("替换:" + newStr2);

        // 转换字节
        byte[] b = str.getBytes();
        System.out.println("字节:" + Arrays.toString(b));

        // 字符串比较
        boolean on = str.equals("123");
        System.out.println("内容比较:" + on);

        // 字符串截取(第一个参数是截取开始位置,截取结束位置)
        String newStr4 = str.substring(9, str.length() - 1);
        System.out.println("截取:" + newStr4);

        //字符串长度
        int length = str.length();
        System.out.println("长度:" + length);

        // 是否为null null返回true,其实就是验证长度是否等于0
        boolean on1 = str.isEmpty();
        System.out.println("null验证:" + on1);

        // 是否已指定字符结尾
        boolean on2 = str.endsWith("3");
        System.out.println("是否已指定字符结尾:" + on2);

        // 是否已指定字符开始
        boolean on3 = str.startsWith("1");
        System.out.println("是否已指定字符开始:" + on3);

        // 合并字符串
        String strCon = str.concat("12321312");
        System.out.println("合并字符串:" + strCon);
  1. 抽象类必须要有抽象方法吗?

    1. 有抽象方法的类肯定是抽象类
    2. 抽象类中可以没有抽象方法
  2. 普通类和抽象类有哪些区别?

    1. 抽象类不能创建对象
    2. 抽象类可能会有抽象方法,普通类不能有抽象方法
    3. 抽象方法必须被子类重写。
  3. 抽象类能使用 final 修饰吗?

    1. 抽象类不能被final修饰
    2. 因为抽象类必须被继承,否则没有意义。而被final修饰的类是不能被继承的。
  4. 接口和抽象类有什么区别?

    1. 接口中只能有方法,而且是抽象的
    2. 抽象类中,可以有属性,抽象方法,非抽象方法,构造器
    3. 接口是实现(implements), 抽象类是继承(extends)
    4. 接口和类是完全不同的类型。一个是class 一个是interface
    5. 抽象类可以向普通类一样继承一个类,实现多个接口。而接口只能继承一个或多个接口
  5. java 中 IO 流分为几种?

    1. InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
    2. OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
  6. BIO、NIO、AIO 有什么区别?

  7. Files的常用方法都有哪些?

容器

  1. java 容器都有哪些?
    1. 数组,String,List,Map,Set
  2. Collection 和 Collections 有什么区别?
    1. Collection是所有集合的最外层接口
    2. Collections是List集合操作类(list排序,聚合函数等)
  3. List、Set、Map 之间的区别是什么?
    1. list与set都继承于Collection
    2. Map {key: value}模式容器
    3. List 集合可以写入重复的值
    4. Set 无法写入重复值
  4. HashMap 和 Hashtable 有什么区别?
    1. HashMap是线程不安全的,Hashtable是线程安全的
    2. HashMap key和value都允许为null, Hashtablekey和value都不允许为null
// Hashtable源码 458行,put时value为null抛出null指针异常
if (value == null) {
    throw new NullPointerException();
}
// Hashtable源码 464行,put时key为null,hashCode()会抛出null指针异常
 int hash = key.hashCode();
 
 
// 而HashMap key为null,hash值设为0
// HashMap源码 338行
 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

  1. 如何决定使用 HashMap 还是 TreeMap?

    1. TreeMap中的元素默认按照keys的自然排序排列。(对Integer来说,其自然排序就是数字的升序;对String来说,其自然排序就是按照字母表排序)
    2. HashMap 是无序的,对象在数组中的位置,取决于key值得hashCode
    3. 如果业务需要满足按照key自然排序,就选择TreeMap
  2. 说一下 HashMap 的实现原理?

    1. HashMap时有数组和链表来实现的容器
    2. 根据key值得hashCode和(数组大小 - 1)根据“&“运算符来定义对象在数组中的位置。
    // 源码:629行
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
    
    // &运算符
    //运算规则:两个数都转为二进制,然后从高位开始比较,如果两个数都为1则为1,否则为0。
    //举例
    //12345 的二进制是    11000000111001
    //85421 的二进制是 10100110110101101
    //12345 & 85421 =  00000000000101001 也就是 41
    System.out.println(12345 & 85421);
    
    1. 如果得到的位置重复,则使用链算法,将对象放下数组此位置最后一链下面
    2. 如果数组被使用超过(数组大小*负载因子),数组就扩容一倍。然后数组下的对象,重新计算位置
    3. 当使用get方法时。会根据key的hashcode和(数组的大小-1)根据&运算来获取数组的下标。如果下标下的第一个节点的key和传过去的key不相等。则根据链表向下遍历
  3. 说一下 HashSet 的实现原理?

    1. HashSet是基于HashMap实现的
    2. 将目标数据最为key值,调用HashMap的put方法来存储,因为HashMap是无序得所以HashSet是无序的,因为将目标数据作为key,所以HashSet不允许插入重复的值
  4. ArrayList 和 LinkedList 的区别是什么?

    1. ArrayList是基于数组实现的,LinkedList是基于双向链表实现的
    2. ArrayList应为是基于数组实现的,所以能更快的定位到存储的对象地址,所以更容易查询和修改,因为每次添加或删除数据,数组都要扩容,所以添加和删除效率低
    3. 因为LinkedList是基于双向链表实现的。散点式存储。(只要让上一个节点记录本次节点的地址,本次节点记录上次节点的信息(所以说是双向量表。每个节点都存储了上个节点和下个节点的地址)),添加效率高。由于没有办法直接定位数据的地址(需要根据根节点或尾节点依次向上或向下查询)所以对查询,修改,删除的效率都不是很高
  5. 如何实现数组和 List 之间的转换?

    1. List转数组可以调用List的toArray方法来转换
    2. 数组转List 可以调用Arrays.asList转换

String[] o = {"22","ddd","fff"};
List<String> list = Arrays.asList(o);
System.out.println(list.toString());

List<String> list1 =new ArrayList<String>();
list1.add("eee");
Object[] p = list1.toArray();
System.out.println(Arrays.toString(p));
  1. ArrayList 和 Vector 的区别是什么?
    1. ArrayList 和 Vector内部都是用数组来实现存储的但Vector的操作方法都是由synchronized修饰。所以ArrayList是线程不安全的,Vector是线程安全的。
  2. Array 和 ArrayList 有何区别?
    1. ArrayList是借助数组实现的,ArrayList可以看做是一个复杂的数组。
    2. ArrayList 提供了一系列数组的操作方法
    3. Array无法扩容,但高效
    4. ArrayList可以扩容,但牺牲了效率
  3. 在 Queue 中 poll()和 remove()有什么区别?
  4. 哪些集合类是线程安全的?
    1. Hashtable, Vector
  5. 迭代器 Iterator 是什么?
    1. Iterator提供了同意遍历操作集合元素的统一接口
  6. Iterator 怎么使用?有什么特点?
    1. 调用集合的iterator()方法,返回Iterator接口实现对象。
    2. 调用Iterator的hasNext()判断是否和有下一个值。
    3. 使用Iterator的next()方法获取下一个值
Set<String> set = new HashSet<String>();
set.add("ddd");
set.add("sss");
set.add("fff");
set.add("ggg");

Iterator<String> value = set.iterator();
while (value.hasNext()) {
    String s = value.next();
    System.out.println(s);
}
  1. Iterator 和 ListIterator 有什么区别?

    1. ListIterator有add()方法,可以向List中添加对象,而Iterator不能
    2. ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
    3. ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
    4. 都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改
  2. 怎么确保一个集合不能被修改?

    1. final可以保证集合的地址不被修改
    2. 使用 Collections.unmodifiableMap();Collections.unmodifiableSet();Collections.unmodifiableList()可以保证集合的内容不被修改
final List<String> listArr = new ArrayList<>();
listArr.add("aa");
listArr.add("bb");
listArr.add("cc");
List list = Collections.unmodifiableList(listArr);
// 在添加会UnsupportedOperationException异常
list.add("fff");

多线程

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

    1. 并行是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU)
    2. 并发指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行。
  2. 线程和进程的区别?

    1. 进程就是正在进行(运行)的程序(软件)
    2. 进程中独立运行的子任务就是一个线程。
  3. 守护线程是什么?

    1. 线程分用户线程和守护线程
    2. Thread.setDaemon(true); 设置线程为守护线程
    3. 当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
  4. 创建线程有哪几种方式?

    1. 就是看Thread类的构造方法有几个,就有几种创建Thread实例的方式.
    2. 集成Thread类创建线程类,应为Thread类实现了Runnable接口。重写run方法
    class ThreadSun extends Thread{
    
        public ThreadSun(String name) {
            super(name);
        }
        public void run() {
            System.out.println(this.getName() + "线程执行");
        }
    }
    ThreadSun threadSun = new ThreadSun("线程1");
    threadSun.start();   
    
    1. 通过Runnable接口创建线程类
    class RunnableSun implements Runnable {
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        public RunnableSun(String name) {
            this.name = name;
        }
    
        @Override
        public void run() {
        System.out.println(this.getName() + "线程执行");
        }
    }
    
    //执行
    Thread threadTwo = new Thread(new RunnableSun("线程1"));
    threadTwo.start();
    
    
    
    等价于
    
    Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getName() + "执行完毕"), "线程1");
    thread.start();
    
    //ThreadGroup 线程组
    Thread()    
    Thread(Runnable target)
    Thread(Runnable target, AccessControlContext acc)
    Thread(ThreadGroup group, Runnable target)
    Thread(String name)
    Thread(ThreadGroup group, String name)
    Thread(Runnable target, String name)
    Thread(ThreadGroup group, Runnable target, String name)
    Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize)
    
  5. 说一下 runnable 和 callable 有什么区别?

    1. 首先线程只接受runnable接口的实现类对象参数
    2. callable需要和FutureTask或Future结合使用才可以创建线程,因为FutureTask继承了runnable
    3. Callalbe接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。
    4. Callable接口的call()方法允许抛出异常;Runnable的run()方法异常只能在内部消化,不能往上继续抛
  6. 线程有哪些状态?

    1. 新建,就绪,运行,阻塞,死亡
    2. 新建: 即单纯地创建一个线程
    3. 就绪: 线程 start 方法执行后,并不表示该线程运行了,而是进入就绪状态,意思是随时准备运行,但是真正何时运行,是由操作系统决定的,代码并不能控制。
    4. 同样的,运行状态的线程,也可能由于失去了 CPU 资源,回到就绪状态,也是由操作系统决定的。这一步中,也可以由程序主动失去 CPU 资源,只需调用 yield 方法。
    5. 死亡:线程运行完毕,或者运行了一半异常了,或者主动调用线程的 stop 方法,那么就进入死亡。死亡的线程不可逆转。
    6. 阻塞: 线程进入运行状态后,可能由于多种原因让线程进入阻塞状态,如:调用sleep()方法让线程睡眠,调用wait()方法让线程等待,调用join()方法、suspend()方法(它现已被弃用!)以及阻塞式IO方法。
  7. sleep() 和 wait() 有什么区别?

    1. sleep() 静态方法,线程睡眠,睡一定时间就醒了。sleep方法不会释放锁的占用,别的线程还是需要继续等待。
    2. wait() Object对象的方法并不是Thread的对象方法,线程等待,必须要采用notify()和notifyAll()方法唤醒该线程。在调用了wait()后,这个线程就会释放它持有的所有同步资源。
    3. wait(long timeout) 超时会被唤醒
    4. wait()一定要使用sycronized进行同步,否则会报“java.lang.IllegalMonitorStateException”异常。这是因为wait方法会释放对象锁,而此时因为没有用sycronized同步,就没有锁,就会报异常。
  8. notify()和 notifyAll()有什么区别?

    1. notifyAll()方法(唤醒所有占用当前锁 wait 线程)
    2. notify()方法(随机唤醒一个占用当前锁 wait 线程)
    3. notify 和 notifyAll 也要放在sycronized修饰的代码块里
package com.lzq.collection;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 开发公司:个人
 * 版权:个人
 * <p>
 * CallableThreadTest
 *
 * @author 刘志强
 * @created Create Time: 2019/9/2
 */
public class CallableThreadTest {

    static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "开始执行");
            synchronized ("ss") {
                System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "获了取锁");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "执行结束");
//                System.out.println(dateFormat.format(new Date()) + ":" +"随机唤醒一个'ss'的等待线程");
//                "ss".notify();
                System.out.println(dateFormat.format(new Date()) + ":" + "唤醒所有'ss'的等待线程");
                "ss".notifyAll();
            }
        }, "线程1");

        Thread thread2 = new Thread(() -> {
            System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "开始执行");
            synchronized ("ss") {
                try {
                    System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "获了取锁");
                    System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "进入等待状态,释放锁。");
                    "ss".wait();
                    System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "被唤醒");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "执行结束");
        }, "线程2");

        Thread thread3 = new Thread(() -> {
            System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "开始执行");
            synchronized ("ss") {
                try {
                    System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "获了取锁");
                    System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "进入等待状态,释放锁。");
                    "ss".wait();
                    System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "被唤醒");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "执行结束");
        }, "线程3");


        Thread thread4 = new Thread(() -> {
            System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "开始执行");
            synchronized ("ff") {
                try {
                    System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "获了取锁");
                    System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "进入等待状态,释放锁。");
                    "ff".wait();
                    System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "被唤醒");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(dateFormat.format(new Date()) + ":" + Thread.currentThread().getName() + "执行结束");
        }, "线程4");
        thread3.start();
        thread2.start();
        thread4.start();
        Thread.sleep(2000);
        thread.start();
    }

}

输出

2019090212:02:41:线程3开始执行
2019090212:02:41:线程2开始执行
2019090212:02:41:线程4开始执行
2019090212:02:41:线程3获了取锁
2019090212:02:41:线程4获了取锁
2019090212:02:41:线程3进入等待状态,释放锁。
2019090212:02:41:线程4进入等待状态,释放锁。
2019090212:02:41:线程2获了取锁
2019090212:02:41:线程2进入等待状态,释放锁。
2019090212:02:43:线程1开始执行
2019090212:02:43:线程1获了取锁
2019090212:02:45:线程1执行结束
2019090212:02:45:唤醒所有'ss'的等待线程
2019090212:02:45:线程2被唤醒
2019090212:02:47:线程2执行结束
2019090212:02:47:线程3被唤醒
2019090212:02:49:线程3执行结束
  1. 线程的 run()和 start()有什么区别?

    1. run() 线程要执行的业务代码方法。runnable 接口的run方法
    2. start() 线程的启动方法
  2. 创建线程池有哪几种方式?

    1. ExecutorService cachedExecutor = Executors.newCachedThreadPool();使用 Executors创建线程池,内置方法比较多。说几个常用的吧。
    2. newFixedThreadPool 定长线程池
    3. newCachedThreadPool 可缓存的线程池
    4. newScheduledThreadPool 定长线程池,可执行周期性的任务
    5. newSingleThreadExecutor 单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行
    6. newSingleThreadScheduledExecutor 单线程可执行周期性任务的线程池
    7. newWorkStealingPool 任务窃取线程池,不保证执行顺序,适合任务耗时差异较大。
  3. 线程池都有哪些状态?

    1. RUNNING(运行)、SHUTDOWN(关闭)、STOP(停止)、TIDYING(内部整理)、TERMINATED(结束)。
    2. 源码
    // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;
    
    1. 线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0!
    2. 调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。此时不能再向线程池里添加新的新线程
    3. 线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。
    4. 当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。 当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。
      当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。
    5. 线程池彻底终止,就变成TERMINATED状态。 线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。
  4. 线程池中 submit()和 execute()方法有什么区别?

    1. submit和execute开启线程执行池中的任务
    2. submit有返回值,而execute没有
    3. execute 只能传Runnable的接口实现类对象
    4. submit 有三个重名方法。可以传Callable的实现类也可以传Runnable的实现类
  5. 在 java 程序中怎么保证多线程的运行安全?

    1. 多线程运行的安全主要体现在当多个线程读写同一个资源时,不可重复读(A线程读到资源后,B线程又改了资源)或写覆盖(A线程改了资源,B线程也改了资源)的情况
    2. 此种问题可以使用同步锁来解决synchronized 或者 Lock
  6. 多线程锁的升级原理是什么?

    1. 锁的优先级:无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁
  7. 什么是死锁?

    1. 两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。
    // 代码
    Thread thread = new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + "尝试获取aa锁");
        synchronized ("aa") {
            System.out.println(Thread.currentThread().getName() + "获取了aa锁");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "尝试获取bb锁");
           synchronized ("bb") {
               System.out.println(Thread.currentThread().getName() + "获取了bb锁");
           }
            System.out.println(Thread.currentThread().getName() + "结束了");
        }
    }, "线程1");
    
    
        Thread thread2 = new Thread(() -> {
    
            System.out.println(Thread.currentThread().getName() + "尝试获取bb锁");
            synchronized ("bb") {
                System.out.println(Thread.currentThread().getName() + "获取了bb锁");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "尝试获取aa锁");
                synchronized ("aa") {
                    System.out.println(Thread.currentThread().getName() + "获取了aa锁");
                }
                System.out.println(Thread.currentThread().getName() + "结束了");
            }
        }, "线程2");
    
        thread.start();
        thread2.start();
    

    打印

    线程1尝试获取aa锁
    线程2尝试获取bb锁
    线程1获取了aa锁
    线程2获取了bb锁
    线程1尝试获取bb锁
    线程2尝试获取aa锁
    
    1. 可以看到当线程1获取bb时和线程2获取aa时死锁了。因为aa正在被线程1占用而bb正在被线程2占用。线程获取不到bb锁继续等待,线程2获取不到aa锁继续等待
  8. 怎么防止死锁?

    1. 使用Lock
    方法说明参数说明
    lock()获得锁
    tryLock()返回boolean, ture代表锁没有被占用,获得锁。false代表锁被占用
    tryLock(long time, TimeUnit unit)返回boolean, 等待time时长后,锁还没有被释放。返回false。time时长内释放了返回true, 并获得锁time:时长, unit:时间类型
    lockInterruptibly()获得锁,和lock()不同,举例:当A线程处于等待时(对执行中的线程无效),其余的线程可调用A线程的interrupt()来中断A线程,A线程直接返回,并抛出InterruptException异常。如果是lock()的话,A线程还是会继续等待并执行,只是给A线程做了个中断标志
    unlock()释放锁
    1. 将其中一个线程设为等待,再由另一个线程唤醒。(这应该不属于解决方案吧,我也不太清楚)
        Thread thread = new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + "尝试获取aa锁");
        synchronized ("aa") {
            System.out.println(Thread.currentThread().getName() + "获取了aa锁");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "尝试获取bb锁");
            try {
                System.out.println(Thread.currentThread().getName() + "释放锁,进去等待状态");
                "aa".wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized ("bb") {
               System.out.println(Thread.currentThread().getName() + "获取了bb锁");
           }
            System.out.println(Thread.currentThread().getName() + "结束了");
        }
    }, "线程1");
    
    
        Thread thread2 = new Thread(() -> {
    
            System.out.println(Thread.currentThread().getName() + "尝试获取bb锁");
            synchronized ("bb") {
                System.out.println(Thread.currentThread().getName() + "获取了bb锁");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "尝试获取aa锁");
                synchronized ("aa") {
                    System.out.println(Thread.currentThread().getName() + "获取了aa锁");
                    System.out.println(Thread.currentThread().getName() + "唤醒等待的线程");
                    "aa".notifyAll();
                }
                System.out.println(Thread.currentThread().getName() + "结束了");
            }
        }, "线程2");
    
        thread.start();
        thread2.start();
    
    
    1. 尽量在业务上避免此情况发生
  9. ThreadLocal 是什么?有哪些使用场景?

    1. 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。相当于每个线程的内部局部对象。
    2. 使用场景,当多个线程共享一个对象,但每个线程执行时,不想让别的线程影响数据的使用时。 具体场景还真想不出来
    package com.lzq.collection;
    
    /**
     * 开发公司:个人
     * 版权:个人
     * <p>
     * ThreadLocalDemo
     *
     * @author 刘志强
     * @created Create Time: 2019/9/3
     */
    public class ThreadLocalDemo {
        static ThreadLocal<String> threadLocal = new ThreadLocal();
    
        public static void main(String[] a) throws InterruptedException {
    
            ThreadDemo threadDemo = new ThreadDemo("线程1", 100);
            ThreadDemo threadDemo2 = new ThreadDemo("线程2", 200);
            ThreadDemo threadDemo3 = new ThreadDemo("线程3", 300);
    
            threadDemo.start();
            Thread.sleep(2000);
            threadDemo2.start();
            Thread.sleep(2000);
            threadDemo3.start();
    
        }
    
    }
    
    class ThreadDemo extends Thread {
    
        private Integer num;
    
        public ThreadDemo(String name, Integer num) {
            super(name);
            this.num = num;
        }
    
        // 重写Run方法
        public void run() {
            System.out.println(this.getName() + ":" + ThreadLocalDemo.threadLocal.get());
            ThreadLocalDemo.threadLocal.set(String.valueOf(num));
            System.out.println(this.getName() + ":" + ThreadLocalDemo.threadLocal.get());
        }
    }
    
    
    

    打印:

    线程1:null
    线程1:100
    线程2:null
    线程2:200
    线程3:null
    线程3:300
    

    可以看出虽然每个线程都操作了静态属性threadLocal。但是每个线程读threadLocal时,都是从初始开始的。就算上个线程改了threadLocal,下个线程读到的threadLocal还是原来的。

  10. 说一下 synchronized 底层实现原理?

  11. == synchronized 和 volatile 的区别是什么?==

    1. volatile让变量每次在使用的时候,都从主内存中取。而不是从各个线程的“工作内存(寄存区)”。写也是写入主内存。
    2. 也就是说volatile修饰的变量如果被另一线程更改,别的线程能获取到修改的值
    3. synchronized是同步锁。
  12. synchronized 和 Lock 有什么区别?

    1. synchronized是java中的一个关键字,也就是说是Java语言内置的特性。
    2. Lock不是Java语言内置的,Lock是一个接口。
  13. synchronized 和 ReentrantLock 区别是什么?

    1. ReentrantLock是Lock的实现类
    2. synchronized无法主动释放锁,以至于等待的线程要一直等待释放锁后才能继续进行
    3. ReentrantLock可以主动释放锁,也可以尝试获取锁,获取不到进行获取不到锁的业务。也可以中断正在等待的线程。也可以一定时间内获取不到锁进行获取不到锁的业务。

    方法 | 说明 | 参数说明
    —|---|–
    lock() | 获得锁 |
    tryLock() | 返回boolean, ture代表锁没有被占用,获得锁。false代表锁被占用 |
    tryLock(long time, TimeUnit unit) | 返回boolean, 等待time时长后,锁还没有被释放。返回false。time时长内释放了返回true, 并获得锁| time:时长, unit:时间类型
    lockInterruptibly() | 获得锁,和lock()不同,举例:当A线程处于等待时(对执行中的线程无效),其余的线程可调用A线程的interrupt()来中断A线程,A线程直接返回,并抛出InterruptException异常。如果是lock()的话,A线程还是会继续等待并执行,只是给A线程做了个中断标志
    unlock() | 释放锁 |

  14. 说一下 atomic 的原理?
    1.

反射

  1. 什么是反射?
    1. JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;
    2. 对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
  2. 什么是 java 序列化?什么情况下需要序列化?
    1. 序列化:将 Java 对象转换成字节流的过程。
    2. 反序列化:将字节流转换成 Java 对象的过程。
    3. 序列化的实现:类实现 Serializable 接口,这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。
    4. 什么情况下需要序列化? 不同内存空间(分布式架构中),共享对象时需要将对象序列化。A服务创建了对象序列化后,存储或传输给B服务。b服务需要反序列化后在内存中就创建了这个对象。
  3. 动态代理是什么?有哪些应用?
  4. 怎么实现动态代理?

对象拷贝

  1. 为什么要使用克隆?

    1. 防止对象被串改
  2. 如何实现对象克隆?

    1. 序列化后反序列化的到全新的对象
    2. 实现Cloneable接口,并重写clone()方法
    3. 使用clone()方法时
    // 浅拷贝
    public TestTwo clone() throws CloneNotSupportedException {
        TestTwo testOne = (TestTwo)super.clone();
        return testOne;
    }    
    
    // 深拷贝
    public TestOne clone() throws CloneNotSupportedException {
        TestOne testOne = (TestOne)super.clone();
        TestTwo testTwo1 = testTwo.clone();
        testOne.setTestTwo(testTwo1);
        return testOne;
    } 
    
    package com.lzq.collection;
    
    /**
     * 开发公司:个人
     * 版权:个人
     * <p>
     * CloneableDemo
     *
     * @author 刘志强
     * @created Create Time: 2019/9/3
     */
    public class CloneableDemo {
    
        public static void main(String[] asg) throws CloneNotSupportedException {
            TestOne testOne = new TestOne();
            testOne.setName("张三");
            testOne.setAge(12);
    
            TestTwo testTwo = new TestTwo();
            testTwo.setName("李四");
            testTwo.setAge(15);
    
            testOne.setTestTwo(testTwo);
    
            // 深拷贝
            TestOne testOne1 = testOne.clone();
    
            // 浅拷贝
            TestOne testOne2 = testOne.clone2();
    
            System.out.println("原对象地址:" + testOne);
            System.out.println("深拷贝对象地址:" + testOne1);
            System.out.println("浅拷贝对象地址:" + testOne2);
    
            // 可以看出不管深拷贝还是浅拷贝。都是创建一个新的对象
    
            System.out.println("原对象引用属性地址:" + testOne.getTestTwo());
            System.out.println("深拷贝对象引用属性地址:" + testOne1.getTestTwo());
            System.out.println("浅拷贝对象引用属性地址:" + testOne2.getTestTwo());
            
            // 但是浅拷贝的对象的引用属性还是指向原地址
        }
    }
    
    class TestOne implements Cloneable {
    
        private String name;
    
        private Integer age;
    
        private TestTwo testTwo;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public TestTwo getTestTwo() {
            return testTwo;
        }
    
        public void setTestTwo(TestTwo testTwo) {
            this.testTwo = testTwo;
        }
    
        public TestOne clone2() throws CloneNotSupportedException {
            TestOne testOne = (TestOne)super.clone();
            return testOne;
        }
    
        public TestOne clone() throws CloneNotSupportedException {
            TestOne testOne = (TestOne)super.clone();
            TestTwo testTwo1 = testTwo.clone();
            testOne.setTestTwo(testTwo1);
            return testOne;
        }
    
    }
    
    class TestTwo implements Cloneable{
    
        private String name;
    
        private Integer age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
        public TestTwo clone() throws CloneNotSupportedException {
            TestTwo testTwo = (TestTwo)super.clone();
            return testTwo;
        }
    }
    
  3. 深拷贝和浅拷贝区别是什么?

    1. 深拷贝—可以拷贝非引用类型的属性,也可以拷贝引用类型(创建新的对象)
    2. 浅拷贝—可以拷贝非引用类型的属性,对于引用属性则还是指向原来的地址

Java Web

  1. jsp 和 servlet 有什么区别?
    1. Servlet 是一种服务器端的Java应用程序
    2. JSP 全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计
    3. jsp经编译后就变成了servlet,jsp本质就是servlet,jvm只能识别java的类,不能识别jsp代码,web容器将jsp的代码编译成jvm能够识别的java类。
    4. JSP侧重视图,Sevlet主要用于控制逻辑。
    5. Servlet中没有内置对象
    6. JSP中的内置对象都是必须通过HttpServletRequest对象,HttpServletResponse对象以及HttpServlet对象得到。
  2. jsp 有哪些内置对象?作用分别是什么?
    1. request:表示HttpServletRequest对象,用户端请求。
    2. response:表示HttpServletResponse对象, 服务端响应
    3. session
    4. applicaton 等等
    5. pageContext:表示一个javax.servlet.jsp.PageContext对象。该对象提供了对JSP页面内所有的对象及名字空间(就是四大作用域空间,如page空间、request空间、session空间、application空间)的访问
  3. 说一下 jsp 的 4 种作用域?
    1. pageContext
    2. request
    3. session
    4. application
  4. session 和 cookie 有什么区别?
    1. cookie以文本格式存储在浏览器上,存储量有限;
    2. session存储在服务端,可以无限量存储多个变量并且比cookie更安全
  5. 说一下 session 的工作原理?
    1. session的内容是保存在服务端的,通过session来区分客户端用户
    2. SessionId通常以Cookie的形式存储在客户端。每次HTTP请求,SessionId都会随着Cookie被传递到服务器端
  6. 如果客户端禁止 cookie 能实现 session 还能用吗?
    1. 不一定,SessionId通常以Cookie的形式存储在客户端
    2. 但是我们也可以自定SessionId的存在位置,比如在url中
  7. spring mvc 和 struts 的区别是什么?
  8. 如何避免 sql 注入?
  9. 什么是 XSS 攻击,如何避免?
  10. 什么是 CSRF 攻击,如何避免?

异常

  1. throw 和 throws 的区别?
    1. throw在方法体内,抛出异常。根据业务可以自己定义这个异常。
    2. throws作用于方法上。像上抛出异常。需要有调用者来处理异常。
  2. final、finally、finalize 有什么区别?
    1. final修饰属性,类,和方法。表示属性不可更改,类不可集成,方法不可重写
    2. finally是try-catch-finally语句的关键字。是try-catch语句中最后执行的代码块
    3. finalize方法是Object提供的的实例方法。当对象不再被任何对象引用时,GC(垃圾回收)会调用该对象的finalize()方法。我们可以在这个方法里做一些资源的释放。
  3. try-catch-finally 中哪个部分可以省略?
    1. finally可以被省略
  4. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
    1. finally会执行。不管try-catch代码块中执行了什么。finally都会被执行
  5. 常见的异常类有哪些?
    1. NullPointerException null指针
    2. 下标越界
    3. 找不到实例等等

网络

  1. http 响应码 301 和 302 代表的是什么?有什么区别?
    1. 301和302都表示重定向
    2. 301是代表永久性转移
    3. 302代表暂时性转移
  2. forward 和 redirect 的区别?
    1. forward 转发:地址栏不改变
    2. redirect 重定向:地址栏改变
  3. 简述 tcp 和 udp的区别?
    1. TCP需要先建立连接,udp无需建立连接
    2. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;
    3. UDP因为无需建立连接,所以不保证可靠性。
    4. TCP效率低,udp效率高
  4. tcp 为什么要三次握手,两次不行吗?为什么?
    1. 为了实现传送的数据,无差错,不丢失,不重复,且按序到达;
    2. 第一次握手 客户端请求服务器要建立连接,等待服务器确认
    3. 第二次握手 服务器收到客户端请求,同意建立连接。并发送信息给客户端
    4. 第三次握手 客户端收到信息,并像服务器发送确认信息。此时tcp连接成功
    5. 可以看出这三次少了哪一次都不行。
  5. 说一下 tcp 粘包是怎么产生的?
  6. OSI 的七层模型都有哪些?
  7. get 和 post 请求有哪些区别?
    1. get适合获取资源的请求
    2. post适合修改资源的请求
    3. get请求url有长度限制
    4. 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据)
    5. 对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
  8. 如何实现跨域?
    1. 服务端返回header头里的Access-Control-Allow-Origin 属性允许来源ip的访问
    2. header(‘Access-Control-Allow-Origin:*’);允许所有来源访问, header(‘Access-Control-Allow-Method:POST,GET’);允许访问的方式
    3. springboot 中在Controller上添加@CrossOrigin就可以了
  9. 说一下 JSONP 实现原理?

设计模式

  1. 说一下你熟悉的设计模式?
  2. 简单工厂和抽象工厂有什么区别?

Spring/Spring MVC

  1. 为什么要使用 spring?
  2. 解释一下什么是 aop?
    1. 面向切面编程
    2. 主要功能:日志记录,性能统计,安全控制,事务处理,异常处理等等。
    3. 将系统代码(日志记录,性能统计,安全控制,事务处理,异常处理等等)和业务代码分离,降低系统的耦合度。减少代码量。
  3. 解释一下什么是 ioc?
    1. ioc控制反转
    2. ioc是一种编程思想,不是一种技术
    3. ioc容器来管理所有的实例,当需要时由ioc来实现注入。减少代码的耦合度。实现代码重复使用。减少实例(对象)的创建
  4. spring 有哪些主要模块?
    1. Spring有七大功能模块,分别是Spring Core,AOP,ORM,DAO,MVC,WEB,Context。
  5. spring 常用的注入方式有哪些?
    1. set注入,构造器注入,依赖注入
  6. spring 中的 bean 是线程安全的吗?
    1. 不是线程安全,(但对于没有属性的实例也算是线程安全)
  7. spring 支持几种 bean 的作用域?
    1. singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例
    2. prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例
    3. request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
    4. session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
    5. globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效
  8. spring 自动装配 bean 有哪些方式?
    1. @Autowired
    2. @Resource(这个注解属于J2EE的),默认按照名称进行装配
    3. 配置文件装配
  9. spring 事务实现方式有哪些?
    1. 基于注解方式@Transactional
    2. 基于配置文件
  10. 说一下 spring 的事务隔离?
    1. spring默认使用数据库的默认级别
    2. 未提交读 :脏读,事务中的修改即使没有提交,对其他事务也是可见的
    3. 提交读: 大多数数据库默认的级别,mysql不是。一个事务所做的修改,对提起事务是不可见的。也就是一个事务的修改只有提交之后,其他事务才可见。 但可能出现幻读,及不可重复读
    4. 可重复度: 一个事务中多次读取的数据是一致的(mysql的默认隔离级别)。即使其他事务的修改已经提交,在本事务中查询结果也是一致的。但可能出现幻读(也就是说 能读到其他事务已提交的插入数据)
    5. 可串行化: 最高的默认级别,强制事务串行执行。效率极其低下
    6. 隔离级别是误了解决脏读, 不可重复读, 和幻读出现的
    7. 不可重复读: 一个事务读取到了另一个事务已经提交修改的数据。导致在事务中多次读取不一致
    8. 幻读: 当前事务在读取某个范围内的记录时,另一个事务在此范围内添加了新的数据,当前的事务再次读取此范围的记录时,产生了幻行。
  11. 说一下 spring mvc 运行流程?
    1. 用户向服务器发送请求,请求被 Spring 前端控制 Servelt DispatcherServlet 捕获(捕获)
    2. DispatcherServlet对请求 URL进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用 HandlerMapping获得该Handler配置的所有相关的对象(包括 Handler对象以及 Handler对象对应的拦截器),最后以 HandlerExecutionChain对象的形式返回;(查找 handler)
    3. DispatcherServlet 根据获得的 Handler,选择一个合适的 HandlerAdapter。 提取Request 中的模型数据,填充 Handler 入参,开始执行 Handler(Controller), Handler执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象(执行 handler)
    4. DispatcherServlet 根据返回的 ModelAndView,选择一个适合的 ViewResolver(必须是已经注册到 Spring 容器中的 ViewResolver) (选择 ViewResolver)
    5. 通过 ViewResolver 结合 Model 和 View,来渲染视图,DispatcherServlet 将渲染结果返回给客户端。(渲染返回)
  12. spring mvc 有哪些组件?
    1. 前端控制器:捕获来自浏览器、前端的请求
    2. 处理器控制器:执行Handler处理器
    3. 处理器映射器:根据url查找Handler处理器
    4. 视图解析器:进行视图解析和渲染,根据逻辑视图名解析成真正的视图
    5. Handler处理器:由适配器去执行Handler处理器
  13. @RequestMapping 的作用是什么?
    1. @RequestMapping声明接口请求方式,请求地址等
  14. @Autowired 的作用是什么?
    1. 自动装配,从ioc容器中找到合适的实例来注入@Autowired标识的参数

Spring Boot/Spring Cloud

  1. 什么是 spring boot?
    1. java开发框架
  2. 为什么要用 spring boot?
    1. 简化了springmvc框架中的配置文件,
    2. 部署简单
    3. 提供了大量的web开发包
  3. spring boot 核心配置文件是什么?
    1. application.yml 或application.properties
  4. spring boot 配置文件有哪几种类型?它们有什么区别?
    1. yml和properties
    2. 主要是书写格式不同
  5. spring boot 有哪些方式可以实现热部署?
  6. jpa 和 hibernate 有什么区别?
  7. 什么是 spring cloud?
    1. 微服务框架
  8. spring cloud 断路器的作用是什么?
    1. 防止服务链雪崩
    2. 当下游服务崩溃或出错时,上游服务都过熔断机制来自己处理相应的业务
  9. spring cloud 的核心组件有哪些?
    1. 注册中心
    2. 网关
    3. 配置
    4. 熔断

Hibernate

  1. 为什么要使用 hibernate?
  2. 什么是 ORM 框架?
  3. hibernate 中如何在控制台查看打印的 sql 语句?
  4. hibernate 有几种查询方式?
  5. hibernate 实体类可以被定义为 final 吗?
  6. 在 hibernate 中使用 Integer 和 int 做映射有什么区别?
  7. hibernate 是如何工作的?
  8. get()和 load()的区别?
  9. 说一下 hibernate 的缓存机制?
  10. hibernate 对象有哪些状态?
  11. 在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?
  12. hibernate 实体类必须要有无参构造函数吗?为什么?

Mybatis

  1. mybatis 中 #{}和 ${}的区别是什么?
    1. #会在参数前后加单引号,$不加单引号
  2. mybatis 有几种分页方式?
  3. RowBounds 是一次性查询全部结果吗?为什么?
  4. mybatis 逻辑分页和物理分页的区别是什么?
  5. mybatis 是否支持延迟加载?延迟加载的原理是什么?
  6. 说一下 mybatis 的一级缓存和二级缓存?
  7. mybatis 和 hibernate 的区别有哪些?
  8. mybatis 有哪些执行器(Executor)?
  9. mybatis 分页插件的实现原理是什么?
  10. mybatis 如何编写一个自定义插件?

RabbitMQ

  1. rabbitmq 的使用场景有哪些?
  2. rabbitmq 有哪些重要的角色?
    1. 交换机,队列
  3. rabbitmq 有哪些重要的组件?
  4. rabbitmq 中 vhost 的作用是什么?
  5. rabbitmq 的消息是怎么发送的?
  6. rabbitmq 怎么保证消息的稳定性?
  7. rabbitmq 怎么避免消息丢失?
  8. 要保证消息持久化成功的条件有哪些?
  9. rabbitmq 持久化有什么缺点?
  10. rabbitmq 有几种广播类型?
  11. rabbitmq 怎么实现延迟消息队列?
  12. rabbitmq 集群有什么用?
  13. rabbitmq 节点的类型有哪些?
  14. rabbitmq 集群搭建需要注意哪些问题?
  15. rabbitmq 每个节点是其他节点的完整拷贝吗?为什么?
  16. rabbitmq 集群中唯一一个磁盘节点崩溃了会发生什么情况?
  17. rabbitmq 对集群节点停止顺序有要求吗?

Kafka

  1. kafka 可以脱离 zookeeper 单独使用吗?为什么?
  2. kafka 有几种数据保留的策略?
  3. kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?
  4. 什么情况会导致 kafka 运行变慢?
  5. 使用 kafka 集群需要注意什么?

Zookeeper

  1. zookeeper 是什么?
  2. zookeeper 都有哪些功能?
  3. zookeeper 有几种部署模式?
  4. zookeeper 怎么保证主从节点的状态同步?
  5. 集群中为什么要有主节点?
  6. 集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?
  7. 说一下 zookeeper 的通知机制?

MySql

  1. 数据库的三范式是什么?
    1.
  2. 一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?
  3. 如何获取当前数据库版本?
  4. 说一下 ACID 是什么?
  5. char 和 varchar 的区别是什么?
  6. float 和 double 的区别是什么?
  7. mysql 的内连接、左连接、右连接有什么区别?
  8. mysql 索引是怎么实现的?
  9. 怎么验证 mysql 的索引是否满足需求?
  10. 说一下数据库的事务隔离?
  11. 说一下 mysql 常用的引擎?
    1. InnoDB 默认引擎, 支持事务。 支持行锁
    2. MyISAM存储引擎, 不支持事务。不支持行锁。只能表锁
    3. 追求快速查询,且数据修改较少选MyISAM。
  12. 说一下 mysql 的行锁和表锁?
  13. 说一下乐观锁和悲观锁?
    1. 乐观锁。假设资源不会占用。 cas机制查询修改。(先查询,更新前再次查询是否和原值一致,一致更改)不一致在重复调用。
    2. 悲观锁。假设资源被占用。
  14. mysql 问题排查都有哪些手段?
  15. 如何做 mysql 的性能优化?

Redis

  1. redis 是什么?都有哪些使用场景?
    1. redis是非关系行数据库
    2. redis是存放在内存中的,读取效率高。
    3. 一般来来说像变动不频繁,数据量大,以及准确度要求不高的时候,可以存放在redis中
    4. 多服务共享数据也可以存放在redis中
  2. redis 有哪些功能?
    1. 存储
  3. redis 和 memecache 有什么区别?
  4. redis 为什么是单线程的?
  5. 什么是缓存穿透?怎么解决?
  6. redis 支持的数据类型有哪些?
    1. String
    2. set
    3. map
    4. list
  7. redis 支持的 java 客户端都有哪些?
  8. jedis 和 redisson 有哪些区别?
  9. 怎么保证缓存和数据库数据的一致性?
  10. redis 持久化有几种方式?
  11. redis 怎么实现分布式锁?
  12. redis 分布式锁有什么缺陷?
  13. redis 如何做内存优化?
  14. redis 淘汰策略有哪些?
  15. redis 常见的性能问题有哪些?该如何解决?

JVM

  1. 说一下 jvm 的主要组成部分?及其作用?
  2. 说一下 jvm 运行时数据区?
  3. 说一下堆栈的区别?
  4. 队列和栈是什么?有什么区别?
  5. 什么是双亲委派模型?
  6. 说一下类加载的执行过程?
  7. 怎么判断对象是否可以被回收?
  8. java 中都有哪些引用类型?
  9. 说一下 jvm 有哪些垃圾回收算法?
  10. 说一下 jvm 有哪些垃圾回收器?
  11. 详细介绍一下 CMS 垃圾回收器?
  12. 新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?
  13. 简述分代垃圾回收器是怎么工作的?
  14. 说一下 jvm 调优的工具?
  15. 常用的 jvm 调优的参数都有哪些?

nginx

大学java的期末复习资源,试题及答案 1、编译Java Application源程序文件将产生相应的字节码文件,这些字节码文件的扩展名为( )。 A.java B..class C.html D..exe 2、下面哪一项字符序列可以作为合法的标识符( )。 A.true B.null C.2018_year D.$2018year 3、下列选项中,( )不属于Java语言的简单数据类型。 A.整数型 B.数组 C.字符型 D.浮点型 4、对于int a[ ]=new int[3],下列叙述错误的是( )。 A. a.length的值是3 B. a[1]的值是1 C. a[0]的值是0 D. a[a.length-1]的值等于a[2]的值 5、用下列哪个代码替换程序标注的【代码】会导致编译错误? A.m-->0 B.m++>0 C.m = 0 D.m>100&&true; public class E { public static void main (String args[ ]) { int m=10,n=0; while(【代码】) { n++; } } } 6、以下关于继承的叙述正确的是( )。 A. 在Java中类不能多继承 B. 在Java中一个类只能实现一个接口 C. 在Java中一个类不能同时继承一个类和实现一个接口 D. 在Java中接口只能单一继承 7、对于下列Cat类,哪个叙述是错误的?( ) A.Cat类只有 2 个构造方法,而且没有无参数的构造方法 B.Cat类有 4 个构造方法 C.Cat (int m)和 Cat (double m)是互为重载的构造方法 D.int Cat (int m)和 void Cat (double m) 是互为重载的非构造方法 class Cat { Cat (int m){ } Cat (double m){ } int Cat (int m){ return 23; } void Cat (double m){ }} 8、下列叙述哪些是正确的( )。 A final 类可以有子类 B abstract类中只能有abstract方法 C abstract类中可以有非abstract方法,但该方法不可以用final修饰 D 不可以同时用final和abstract修饰一个方法 9、假设D类有如下定义,设d是D类的一个实例对象,下列语句调用错误的是 ( )。 class D{ int i; static String s; void method1(){} static void method2(){}} A.d.method1(); B.D.method2(); C.D.method1(); D.System.out.println(d.i); 10、将下列( )哪个代码替换下列程序中的【代码】不会导致编译错误。 A.public int f(){return 100+M;} B.int f(){return 100;} C.public double f(){return 2.6;}。 D.public abstract int f();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值