Java基本知识要点总结

Java基础

Java容器

  • Java集合概述
  • 说说 List,Set,Map 三者的区别?
  • 如何选用集合?
  • Iterator 迭代器
  • 有哪些集合是线程不安全的?怎么解决呢?
  • Arraylist 和 Vector 的区别?
  • Arraylist 与 LinkedList 区别?
  • 说一说 ArrayList 的扩容机制吧
  • ArrayList如何进行数组拷贝,深拷贝和浅拷贝
  • Comparable 和 Comparator 的区别
  • 比较 HashSet、LinkedHashSet 和 TreeSet 三者的异同
  • HashMap 和 Hashtable 的区别
  • HashMap 和 HashSet 区别
  • HashMap 和 TreeMap 区别
  • HashSet 如何检查重复
  • HashMap 的底层实现(JDK1.8 之前 / JDK1.8 之后)
  • HashMap 的长度为什么是 2 的幂次方
  • HashMap 多线程操作导致死循环问题
  • HashMap 有哪几种常见的遍历方式?
  • ConcurrentHashMap 和 Hashtable 的区别
  • ConcurrentHashMap 线程安全的具体实现方式/底层具体实现(JDK1.8 之前 / JDK1.8 之后)
  • Collections 工具类排序操作
  • Collections 工具类查找、替换操作
  • Collections 工具类同步控制
  • 快速失败(fail-fast)
  • 安全失败(fail-safe)
  • ArrayList 源码
  • LinkedList 源码
  • HashMap(JDK1.8)源码
  • ConcurrentHashMap源码
  • 参考
    Java集合框架常见面试题
    Java 集合框架
    ArrayList的深拷贝与浅拷贝
    ArrayList clone()– ArrayList深拷贝和浅拷贝

并发

Java并发编程之美(2018)

  • 线程创建的三种方式
  • 线程notify() / notifyAll() / wait() 方法
  • 线程的join() 方法
  • 线程的sleep() 方法
  • sleep()和wait()的区别

区别是:
1. sleep()不释放同步锁,wait()释放同步锁
2. sleep(milliseconds)可以用时间指定来使他自动醒过来,如果时间不到你只能调用interreput()来强行打断;wait()可以用notify()直接唤起.
3. 这两个方法来自不同的类分别是Thread和Object
4. wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在
任何地方使用
synchronized(x){ x.notify() //或者wait() }
5. sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常

  • 线程的yield() 方法

  • 线程中断 / interrupt()方法;InterruptedException异常;通过interrupt优雅地退出一个线程

  • 线程死锁,避免死锁

  • 守护线程;setDaemon(true);JVM等待所有线程退出后才结束;jps命令的使用

  • ThreadLocal类 / InheritableThreadLocal类

  • 如何引起线程安全问题;读取-修改-写入操作

  • Java多线程的内存模型
    在这里插入图片描述

  • Java共享变量的内存可见性问题;定义;如何产生;如何解决

  • synchronized关键字;synchronized关键字在内存模型中的内存语义;如何解决共享内存不可见和原子性问题
    synchronized(修饰方法和代码块)

  • volatile关键字;如何解决共享内存不可见问题,无法解决原子性问题

  • 指令重排和volatile关键字

  • Java中的原子性和CAS操作

  • CAS概念梳理

  • CAS操作和独占锁在实现原子性上开销的差距;java-cas与锁比较

  • Unsafe类(主要包含CAS操作,无法普通调用)

  • 伪共享;定义,结合多线程内存模型;多线程和单线程条件下的区别;如何避免

  • 乐观锁和悲观锁

  • 公平锁和非公平锁;ReentrantLock

  • 独占锁和共享锁;ReadWriteLock

  • 可重入锁;synchronized实例;解释代码;原理实现
    Synchronized可重入锁分析

  • 自旋锁;CPU占用和内核切换的权衡

  • Random类;nextInt方法迭代种子;多线程产生随机数时出现的重复问题

  • 利用AtomicLong原子CAS操作实现,不停轮询,CPU占用高

  • ThreadLocalRandom,类似ThreadLocal实现,每个线程自己维护一个seed

  • current()方法和nextInt()方法

  • AtomicLong类如何实现内存可见和原子性;

  • LongAdder类对AtomicLong类的改进;Cell子类的结构;add() / reset() / sum()

  • LongAccumulator类;accumulate() / longValue()

  • CopyOnWriteArrayList类;使用了Arrays.copyOf()方法获得数组拷贝;setArray()方法覆盖原有数组

  • CopyOnWriteArrayList类弱一致性的迭代器;即迭代器传递的是数组引用,但是如果在修改线程start之前创建迭代器,一切增删改操作都无法在迭代器生效

  • LockSupport类;基类;park()方法和unpark()方法

  • 抽象同步队列AQS;双向队列,状态量state,条件变量

  • 生产者-消费者模型

  • 独占锁ReentrantLock;state与可重入机制

  • lock()方法以及如何实现①返回false加入AQS阻塞队列;②state为0;③当前线程为锁持有者时可重入;④公平锁与非公平锁

  • unlock()方法以及state值①为0时释放锁②对可重入锁state值减1

  • 条件队列与阻塞队列Node节点的轮换;条件变量的await()和signal();

  • 读写锁ReentrantReadWriteLock;state通过位运算获得前16位作为读锁,后16位作为写锁

  • 写锁的lock()方法,①state值不为0,此时为读锁或者非当前线程则返回false添加进AQS阻塞队列,当为可重入写操作时加1;②state为0

  • 写锁的unlock()方法,①可重入次数减1②判断可重入次数是否为0,当为0则释放锁且激活阻塞队列的一个线程

  • 读锁的lock()方法,①如果写锁被占用且非当前线程则放入AQS阻塞队列(即当前为写锁依然能读)②增加读锁的计数count

  • 并发队列;使用锁实现阻塞队列,使用CAS实现非阻塞队列

  • ConcurrentLinkedQueue实现线程安全的无界非阻塞队列;底层使用单向链表,head、tail节点都设置为volatile保证内存可见性,入队使用casNext的CAS操作,出队使用CAS操作将头部节点设置为null并重新设置头节点后移除该节点

  • LinkedBlockingQueue使用独占锁实现有界阻塞队列;底层使用单向链表,使用AtomicInteger计算队列元素个数,拥有两个锁takeLock和putLock分别控制出队入队的原子性以及两个条件变量notEmpty和notFull用来存放阻塞的线程,实现生产者-消费者模型;

  • offer()方法非阻塞,使用putLock锁保证入队的原子性,随后根据队列中元素个数多少,进行notFull和notEmpty的signal(),注意调用条件变量的方法需要获取对应的锁;put()方法在队列已满时需要调用notFull的await()方法把线程放入条件队列,并释放putLock锁,判断await()需要在while (临界条件)下,为了避免出现虚假唤醒。

  • poll()方法非阻塞,使用takeLock锁保证出队的原子性,并递减计数器,随后根据队列中元素个数多少,进行notEmpty和notFull的signal();take()方法在队列为空时需要调用notEmpty的await()方法把线程放入条件队列,并释放takeLock锁

  • remove()方法删除队列的指定元素,需要双重加锁,通过遍历队列来删除,注意解锁顺序应与加锁顺序相反

  • ArrayBlockingQueue使用独占锁实现线程安全的有界阻塞队列;底层使用有界数组,拥有一个锁lock保证出入队的原子性,这也使得同一时间只有一个线程能进行出入队操作,拥有两个条件变量notEmpty和notFull用来存放阻塞的线程

  • offer()/poll()和put()/take()与LinkedBlockingQueue类似

  • PriorityBlockingQueue实现线程安全的带优先级的无界阻塞队列,底层使用堆数组实现,需要对象满足Comparable接口,包含一个自旋锁allocationSpinLock,其值为{0, 1},使用CAS保证只有一个线程可以扩充队列,包含一个独占锁lock控制出入队的原子性,只有notEmpty条件变量没有notFull(无界)

  • offer()方法非阻塞,使用lock保证入队的原子性,如果当前元素个数大于capacity需要进行扩容(无界性保证),tryGrow()方法先释放锁使得其他出入队线程可以获得锁,然后判断并使用CAS设置自旋锁的值,得到扩容后的新数组,再获取锁后将原数组拷贝至新数组,注意对于其他未能获得自旋锁进行扩容的线程,将一直while原地自旋等待扩容完成,扩容完成后使用堆操作入队,计数器加1,并通知notEmpty条件队列

  • poll()方法非阻塞,需要获取lock锁保证出队的原子性,使用堆操作弹出堆顶元素

  • put()方法仍然是非阻塞的(无界),take()方法在队列为空时需要阻塞放入条件队列

  • DelayQueue实现线程安全的带延迟时间的无界阻塞队列,内部基于PriorityBlockingQueue实现,其中元素需要实现继承了Comparable接口的Delayed接口,poll()/take()方法用于移除其中的过期元素

  • 使用线程池的好处

  • ThreadPoolExecutor,工厂方法产生newCachedThreadPool, newFixedThreadPool, newSingleThreadExecutor

  • 成员ctl原子变量同时记录线程池状态(种类)和当前线程个数;workQueue作为线程的阻塞队列;mainLock独占锁提供阻塞队列出入队的原子性,termination为条件变量;加入线程池的任务包装为Worker,自身实现了不可重入的独占锁,state值为{0, 1}

  • execute()方法;作用是提交任务到线程池中运行;如果当前线程个数小于核心线程池个数,则进行addWorker()方法提交任务运行,如果当前线程个数大于等于核心线程池个数,且处于Running状态,则移入阻塞队列,如果此时阻塞队列已满,则执行拒绝策略。addWorker()方法首先判断线程池的状态,然后使用CAS操作增加一个线程,随后创建一个Worker对象,将新任务添加进线程池并执行

  • shutdown()方法;先进行权限检查,再设置线程池的状态,然后为所有空闲线程设置为interrupt(为所有未中断且Worker对象无锁),注意interrupt()需要先获得Worker锁

  • shutdownNow()方法;与shutdown()不同的是,需要中断空闲线程和正在执行任务的线程

  • awaitTermination()方法;获取锁后循环询问是否到达TERMINATED状态,等待时间超时后才返回

  • CountDownLatch;使用countDown()和await()控制多个线程的同步,注意需要提前指定state的个数,state为0则继续执行。CountDownLatch和WaitGroup

  • CyclicBarrier;相比于CountDownLatch,多了count和parties,当一轮结束完成后执行预设任务再重置,通过await()方法将线程在AQS阻塞队列和trip条件队列之间转换,适用于分段任务有序执行的场景

  • Semaphore信号量;相比于CountDownLatch,无需提前指定state值,通过release()增加信号量,在aquire()方法处比较已有信号量和所需信号量,小于0则阻塞当前线程,唤醒后重新进入acquire()流程

Java并发面试知识点

  • Java中线程的生命周期以及转换
    在这里插入图片描述

  • 为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?

  • synchronized关键字的三种修饰方式

  • 双重校验锁实现单例模式

  • synchronized关键字实现功能的底层原理

  • synchronized关键字底层轻量级的优化

  • synchronized与ReentrantLock的区别

  • volatile关键字的两个作用

  • CPU缓存模型和JMM模型

  • 并发编程需要满足的三个特性(原子性、内存可见性、有序性)

  • ThreadLocal及ThreadLocalMap原理

  • 为什么要使用线程池?

  • Runnable和Callable接口的区别

  • 示例代码:Runnable/Callable+ThreadPoolExecutor

  • 线程池execute()方法和submit()方法以及Future接口及get()阻塞方法

  • 线程池shutdown()方法和shutdownNow()方法

  • ThreadPoolExecutor的构造函数的参数
    在这里插入图片描述

  • ThreadPoolExecutor的饱和策略

  • 线程池添加任务的流程图
    在这里插入图片描述

  • FixedThreadPool / SingleThreadExecutor / CachedThreadPool 构造、执行任务过程、OOM可能性

  • CPU密集型和I/O密集型任务线程池大小的确定(N+1 / 2N)

  • JUC包中的4种原子类(AtomicInteger等)

  • AtomicInteger类的使用/ConcurrentLinkedQueue的使用

  • AtomicInteger如何实现线程安全(CAS+volatile)

  • AtomicIntegerArray类的使用

  • AtomicReference类的使用

  • AQS的原理

  • AQS的常用组件(Semaphore/CountDownLatch/CyclicBarrier)及使用

  • 乐观锁和悲观锁的概念及应用场景

  • 乐观锁的两种常见实现方式(版本号、CAS)

  • 乐观锁的三个缺点(ABA问题、自旋开销、JDK1.5之前只能保证一个共享变量(AtomicReference))

  • CAS与传统锁的应用场景

  • synchronized关键字JDK1.6之后的改进(自旋后阻塞,竞争切换后继续竞争锁);在线程冲突较少的情况下,可以获得和CAS类似的性能;而线程冲突严重的情况下,性能远高于CAS

  • Java常用并发容器的使用(api与非线程安全的基本相同)和原理

  • ConcurrentHashMap;线程安全的HashMap,ConcurrentHashMap与HashTable的区别,以及JDK1.7的分段锁实现和JDK1.8的节点锁的实现

  • CopyOnWriteArrayList;适用于读多写少的ArrayList,且读写不会冲突,读操作不上锁,写操作通过copy一个容量+1的数组来实现扩容

  • ConcurrentLinkedQueue;非阻塞队列,由于使用了CAS算法进行offer等操作,所以性能很高,但是冲突很强的时候也会碰到CAS一样的问题

  • BlockingQueue由于使用了锁和条件变量,所以是阻塞队列,可实现"生产者-消费者"问题

    • ArrayBlockingQueue;实现上述接口的有界队列,一旦创建数组底层不可改变,注意出入队都只能获取同一个锁
    • LinkedBlockingQueue;基于单向链表实现,原则上是无界队列,也可以限制为有界队列,出入队由不同的锁控制
    • PriorityBlockingQueue;基于堆的结构实现,无界队列,没有notFull条件变量,可以自动扩容
  • ConcurrentSkipListMap;使用跳表(有序链表)以空间换时间的方式实现Map接口,能以O(logN)获取元素,插入删除元素,同时使用分段锁达到不同分链表快速并行,同时,所有元素也是有序的
    在这里插入图片描述

JVM

  • Java的内存区域是什么样子,以及JDK1.8的变化
    在这里插入图片描述

  • 内存区域中各部分的作用

  • Java对象是如何创建的

  • 一个主类中执行某方法执行时的JVM内部过程

  • Java对象在内存中的布局(对象头、实例数据和对齐填充)

  • Java对象的访问定位

  • String类和常量池技术,字符串拼接带来的问题

  • Integer的“==”比较

  • JVM中堆空间的基本结构
    在这里插入图片描述

  • 对象如何经历Minor GC从Eden区→Survivor区(from/to)→老年区

  • 新生代晋升到老年代的动态年龄

  • Partial GC和Full GC

  • 判断对象是否失效(引用计数法、可达性分析法)

  • 垃圾收集算法(标记-清除、标记-整理、复制算法、分代收集策略)

  • 垃圾收集器
    在这里插入图片描述

  • 重点了解ParNew/CMS/G1

——ParNew,常用于新生代中如Eden区和Survivor区之间的移动

在这里插入图片描述

——CMS,如老年区的并发标记清除

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值