一、HashMap和ConcurrentHashMap

HashMap底层源码分析

如何解决Hash碰撞的(延伸出Hash冲突的几种解决方法)

通过h & (table.length -1)来得到该对象的保存位,而HashMap底层数组的长度总是2的n次方,这是HashMap在速度上的优化

当length总是2的n次方时,h& (length-1)运算等价于对length取模,也就是h%length,但是&比%具有更高的效率

put过程

 

                 

  

 扩容机制

 

 get过程

 

HashMap的初始化容量为什么是2的次幂

https://www.iteye.com/topic/539465

为什么HashMap长度大于8才转换为红黑树

 

HashMap和HashTable的区别?

https://www.cnblogs.com/williamjie/p/9099141.html

HashMap和TreeMap比较?

HashMap,HashTable,CourrentHashMap的key和value是否可为null?那为什么这么设计?

CourrentHashMap源码分析

二、JUC(java.utils.concurrent)

并发编程的的三个概念(特性)?为什么会有Volatile关键字?volatile关键字的两层语义!!volatile底层原理!!

原子性 ==> 不可分割、完整性,即某个线程正在做某个具体业务时,中间不可以被加塞或者被分割,需要整体完整,要么同时成功,要么同时失败 

可见性 ==> 当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看到修改的值

有序性 ==> 为了提高性能,JVM在编译Java代码,或者CPU在执行JVM字节码的时候,对现有的指令顺序进行重新排序

单线程环境里面确保程序最终执行结果和代码顺序执行的结果一致

处理器在进行重排顺是必须要考虑指令之间的数据依赖性

多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程中使用的变量能否保证一致性时无法确定的,结果无法预测 

volatilejava虚拟机提供的轻量级同步机制 ==> 保证可见性、不保证原子性、禁止指令重排

volatile底层原理

volatile的底层是通过lock前缀指令、内存屏障来实现的

https://www.jianshu.com/p/2643c9ea1b82

JMM(Java内存模型)

JMMJava Memory Model)本身是一种抽象的概念,并不真实存在,他描述的是一组规则或规范。

通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。

JMM关于同步的规定:
  1. 线程解锁前,必须把共享变量的值刷新回主内存
  2. 线程加锁前,必须读取主内存的最新值到自己的工作内存
  3. 加锁解锁时同一把锁
由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有的成为栈空间),工作内存是每个线程的私有数据区域,而java内存模型中规定所有变量都存储在主内存,主内存
是贡献内存区域,所有线程都可以访问,线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝到自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回
主内存,不能直接操作主内存中的变量,各个线程中的工作内存中存储着主内存的变量副本拷贝,因此不同的线程件无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成。
期间要访问过程如下图: 

在哪些地方用过volatile

双重检查锁机制(Double Check Lock)

 

步骤2和步骤3不存在数据依赖关系,而且无论重排前还是重排后程序的执行结果在单线程中并没有改变,

因此这种重排优化时允许的,如果3步骤提前于步骤2,但是instance还没有初始化完成

所以当一条线程访问instance不为null时,由于instance示例未必已初始化完成,也就造成了线程安全问题

基于volatile的解决方案

为解决以上问题,可以将SingletongDemo实例上加上volatile

private static volatile SingletonDemo instance = null;

什么是线程安全?产生线程不安全的原因是什么?Java线程安全的类?

在堆内存中的数据由于可以被任何线程访问到,在没有限制的情况下存在被意外修改的风险

 

CopyOnWriteArrayList.add方法

 

CAS原理(CompareAndSwap 比较并交换)

AtomicInteger为例

Unsafe

CAS核心类,由于Java方法无法直接访问底层系统,需要通过本地(native)方法来访问,Unsafe相当于一个后门,基于该类可以直接操作特定内存数据。

Unsafe类存在于 sun.misc 包中,其内部方法操作可以像C的指针一样直接操作内存,因为JavaCAS操作的执行依赖于Unsafe类的方法 

Unsafe类中的所有方法都是native修饰的,也就是说Unsafe类中的方法都直接调用操作系统底层资源执行相应任务 

CAS缺点               

如果一个变量初次读取的时候是 A 值,它的值被改成了 B,后来又被改回为 A,那 CAS 操作就会误认为它从来没有被改变过

J.U.C包提供了一个带有标记的原子引用类 AtomicStampedReference来解决这个问题,它可以通过控制变量值的版本来保证 CAS 的正确性

公平锁/非公平锁;可重入锁;独享锁/共享锁;乐观锁/悲观锁;手写自旋锁

公平锁/非公平锁

公平锁是指多个线程按照申请锁的顺序来获取锁 

非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程优先获取锁,在高并发的情况下,有可能会造成优先级反转或者饥饿现象 

可重入锁(递归锁) 

指的时同一线程外层函数获得锁之后,内层递归函数仍然能获取该锁的代码,在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁

也就是说,线程可以进入任何一个它已经拥有的锁所同步着的代码块

ReentrantLock/Synchronized 就是一个典型的可重入锁

可重入锁最大的作用是避免死锁

ReentrantReadWriteLock源码分析

自旋锁

是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环

/**
 * 手写自旋锁
 * @author 
 */
public class SpinLock {
    AtomicReference<Thread> atomicReference = new AtomicReference<>();
    
    public void lock() {
        Thread thread = Thread.currentThread();
        while(!atomicReference.compareAndSet(null, thread)) {
            
        }
    }
    
    public void unlock() {
        Thread thread = Thread.currentThread();
        atomicReference.compareAndSet(thread, null);
    }
}

synchronized和ReentrantLock

synchronized三种应用方式;为什么能实现实现内存可见性;底层原理

 

 

 

synchronized修饰静态方法和成员方法的区别

ReentrantLock类的实现原理

synchronized和ReentrantLock的异同

阻塞队列

 

 

 

 

阻塞队列的用途

生产者消费者模式

线程池

消息中间件

阻塞队列的实现原理

使用通知模式实现 ==> 当生产者往满的队列里添加元素时会阻塞住生产者,当消费者消费了一个队列中的元素后,会通知生产者当前队列可用

 

 

线程池

线程池的好处

线程池任务执行流程!!

 

 

Java中的ThreadPoolExecutor类!线程池涉及到的参数!

 

线程池的状态?

https://blog.csdn.net/l_kanglin/article/details/57411851

任务缓存队列及排队策略,如何自定义拒绝策略?

线程池的种类?

 

 

配置线程池大小,根据CPU密集和IO密集划分

ThreadLocal介绍,实现原理!!ThreadLocal是如何做到为每一个线程维护变量的副本的呢?ThreadLocal和同步机制的区别

内存泄漏和内存溢出,常见的内存泄露(介绍一下HashMap泄露的场景),避免内存泄漏的几点建议?如何定位找到内存泄漏!!

设计模式的单例和工厂是面得最多的!单例的几种实现方式,一般写典型的双重检查锁定,因为会延伸出volatile,线程安全这些。

饿汉式,线程安全为什么不用这个方式呢,简单又线程安全?然后是抽象工厂模式和工厂方法模式区别?JDK或者Spring当中哪里用了设计模式?