全栈知识点
关键字: synchronized详解 | Java 全栈知识体系
1.java反射机制
1.1 类加载过程
1.1.1 类的加载过程:
源文件经过编译后得到.class文件,被jvm加到内存中,在运行时加载和执行;
加载过程:加载——连接(验证——准备——解析)——初始化
1.1.2 双亲委派模型:
加载时自下往上获取类是否加载,加载时从上往下尝试加载,保证类只被加载一次,运行期间一个类只有一个class对象产生;
Bootstrap ClassLoader启动类加载器
Extension ClassLoader扩展类加载器
App ClassLoader应用程序类加载器
继承ClassLoader自定义类加载器
静态加载和动态加载:
new()初始化一个类视为静态加载,加载时异常是error,NoClassDefFoundError;
class.forName()视为动态加载(运行时可改变程序结构和变量类型),加载时异常ClassNotFoundException,checked异常,写代码时需要catch
1.2.java反射机制
反射机制:运行时可获取任何一个类的方法和属性,可调用任何对象的方法和属性
反射获取属性和方法:
1.object——getClass,需要已经有类的对象存在;
2.静态的class属性,如String.class,可返回相关联的class对象,不需要类的对象存在;
3.class类的静态方法forName(String className) --className为全路径包名
通过反射生成对象:
1.class对象的newInstance()
2.通过class对象——Constructor对象——Constructor的newInstance()创建对象 -- 可指定构造器类的实例,newInstance()方法的本质是调用类的无参Public构造方法
获取某个类的构造方法 getDeclaredConstructor(不分public);
获取类的成员方法: getMethod(),getDeclaredMethod(不分public)
获取类的成员变量(成员属性:getDeclaredField(不分public),获取私有setAccessible(true)
java基础之反射机制_悟笙的博客-CSDN博客_java 反射
Java基础篇:反射机制详解_张维鹏的博客-CSDN博客_java反射机制原理详解
Java虚拟机:对象创建过程与类加载机制、双亲委派模型_张维鹏的博客-CSDN博客
3.AQS(AbstractQuenedSynchronizer 抽象的队列式同步器)
3.1.核心思想:
被请求的共享资源空闲——当前请求资源的线程设置为有效,共享资源设置为锁定状态;
如果被请求的共享资源被占用——线程阻塞等待,被唤醒时锁分配的机制,用CLH队列(虚拟双向队列,无队列实例,通过节点关联)锁实现;
volatile修饰共享变量state,线程通过CAS去改变状态符,成功则获取锁成功,失败则进入等待队列,等待被唤醒;
3.2.资源共享方式:
独占式:exclusive, 只有ReentrantLock可以执行;
共享:share,有CountDownLatch、ReadWriteLock等可以执行;
同时实现独占和共享两种方式:如ReentrantReadWriteLock;
AQS详解(面试)_mulinsen77的博客-CSDN博客_aqs
可重入锁,共享模式,互斥锁(源码解析)
Java并发之AQS详解 - waterystone - 博客园
LockSupport:
阻塞park(),释放unpark(),无先后顺序,permit只有0和1,多次park()不会累加;
syncronized:
等待wait(), 唤醒notify(),成对出现,有先后顺序,通过底层monitor对象完成,
不需要手动释放锁,
非公平锁,不可中断,
唤醒机制:随机唤醒或者全部唤醒(notifyAll());
作用域
不能被继承
加在对象时,同步的对象是实例,同步的是非静态方法
加在类XXXX.class或者代码块(方法)(可以对静态方法同步
synchronized 作用域问题_程序媛-CSDN博客_synchronized作用域
深入分析Synchronized原理(阿里面试题) - aspirant - 博客园
synchronized的四种作用域以及不能被继承解析 - 从此寂静无声 - 博客园
ReentrantLock:
Sync类实现,需要手动释放锁
可设置,true 公平锁(FIFO),false非公平锁
可中断,中断方法:
tryLock(long timeout TimeUnit unit),
lockInterruptibly()放代码块中调用,调用interrupt方法可中断
唤醒机制: 可设置条件精准唤醒,前驱节点的出队或阻塞线程被中断
深入理解 AQS 底层实现原 park unpar理_庸人庸的博客-CSDN博客_aqs
ReentrantLock公平锁和非公平锁加锁和释放过程(源码解析和流程图讲解比较清晰)
对比:
相同:可协调多线程同步;互斥锁和可见;可重入锁
不同:
1. ReentrantLock显示地获得,释放锁,synchronized隐式获得释放锁
2. ReentrantLock可响应中断,可轮回,synchronized是不可以响应中断的
3. ReentrantLock是API级别的,synchronized是JVM级别的
4. ReentrantLock可以实现公平锁
5. ReentrantLock通过Condition可以绑定多个条件
6. 底层实现不一样,synchronized是同步阻塞,使用的是悲观并发策略,lock是同步非阻塞,采用的是乐观并发策略。
7. Lock是一个接口,而synchronized是java中的关键字,synchronized是内置的语言实现
8. synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而 Lock 在发生异常时,如果没有主动通过 unLock()去释放锁,则很可能造成死锁现象, 因此使用 Lock 时需要在 finally 块中释放锁。
synchronized和ReentrantLock的区别_淮水竹亭-CSDN博客
java面试题:java中断,synchronized和ReentrantLock能否中断_我是方小磊的博客-CSDN博客_reentrantlock中断
3.3.CAS底层原理:
比较交换技术,内存地址V,期望值E,新值N,经过对比期望值与 V,决定是否交换,相等将N更新
a-B-a问题,添加version版本号控制
多次比较效率低,某个线程取值与期望值一直不相等可能无限循环
1)确保对内存的读-改-写操作原子执行。处理器会使用总线锁 或 缓存锁来保持原子性。
2)禁止该指令,与之前和之后的读和写指令重排序。
3)把CPU写缓冲区中的所有数据刷新到内存中,使其它CPU缓存失效。
深入图解AQS实现原理和源码分析_Seky_fei的博客-CSDN博客
CAS原理解析 CAS底层 - YoungDeng - 博客园
5.java多线程并发
Java中如何保证线程安全性_阿梨喜欢吃榴莲的博客-CSDN博客_如何保证线程安全
如何确保线程安全_笑笑生的博客-CSDN博客_怎么确保线程安全
5.1 final原理:
修饰的是一个基本数据类型数据:这个数据的值在初始化后将不能被改变;;
当final修饰的是一个引用类型数据时:也就是修饰一个对象时, 引用在初始化后将永远指向一个内存地址, 不可修改. 但是该内存地址中保存的对象信息可以修改的
修饰的类时,该类不可被继承,该类的方法隐式指定为final方法;
修饰方法时,该方法不能被重写
深入理解final关键字(详解)_念念不忘,必有回响-CSDN博客_final关键字
浅析Java中的final关键字 - Matrix海子 - 博客园
5.2 volatile原理:
共享和防止指令重排序,但是不能保证原子性
lock指令:
锁总线,其它CPU对内存的读写请求都会被阻塞,直到锁释放,不过实际后来的处理器都采用锁缓存替代锁总线;
lock后的写操作会回写已修改的数据,同时让其它CPU相关缓存行失效,从而重新从主存中加载最新的数据
可见性:写操作StoreStore屏障,写操作之后StoreLoad,将最新变量刷回内存;读之前load读取主内存的最新变量,读之后LoadLoad和LoadStore内存屏障
深入理解Volatile关键字及其实现原理_泽宇的博客-CSDN博客
Volatile禁止指令重排序(三) - MXC肖某某 - 博客园
volatile是怎么保障内存可见性以及防止指令重排序的?_做最亮的星星-CSDN博客_volatile如何保证内存可见性
atomicLong:对长整形进行原子操作
incrementAndGet()
volatile修饰value ,CAS更改
volatile和Atomic_dzyls的笔记-CSDN博客
Java原子类--AtomicLong - ken007 - 博客园
5.3 线程池
线程的生命周期:创建start——就绪runnable(阻塞)——run——stop
方便线程的管理,可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,减少创建和销毁的内存开销
ThreadPoolExecutor
核心线程数量corePoolSize
最大线程数量maximumPoolSize
keepAliveTime:核心线程以外的线程回收时间设置
workQueue:FIFIO原则(先进先出)
SynchronousQueue 直接提交:该QUEUE中,每个插入操作必须等待另一个线程的对应移除操作。
LinkedBlockingQueue 无界队列:所有corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize
ArrayBlockingQueue 有界队列 不推荐
handler:拒绝策略
RejectedExecutionHandler:拒绝四种策略
1. CallerRunsPolicy:线程调用运行该任务的 execute本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度;
2.AbortPolicy:处理程序遭到拒绝将抛出运行时RejectedExecutionException
3.DiscardPolicy:删除,但是不抛出异常
4.DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的(等待时间最久)任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)
Java线程池的底层实现与使用 - StoneGeek - 博客园
深入理解线程和线程池(图文详解)_weixin_40271838的博客-CSDN博客_线程池
5.4 线程的销毁
核心线程超时删除:allowCoreThreadTimeOut=true
1当没有超过核心线程时,不会销毁线程
2当超过核心线程数:再判断,如果超过最大值,则销毁;如果timeout过,则销
java 线程池 配置_Java手动配置线程池过程详解_马斯克·贾的博客-CSDN博客
Java线程池的allowCoreThreadTimeOut参数_weixin_33859231的博客-CSDN博客
6.redis
6.1 分布式锁:
保证同一时间只能有一个客户端对共享资源进行操作,解决多个服务资源共享的问题
标志位(唯一标识)+超时设置+finally释放锁
【剑指Offer】Redis 分布式锁的实现原理看这篇就够了_龙台的技术笔记-CSDN博客_redis分布式锁实现原理
Redis实现分布式锁原理与实现分析_jp413670706的专栏-CSDN博客_redis分布式锁实现原理
基础信息:
主要依赖物理内存,一个字符串类型最大容量512M
数据类型:String、List、Set、Sorted Set、hashes
史上最全Redis面试题及答案_xiaozhegaa的博客-CSDN博客_redis面试题及答案
zset:
redis zset底层实现原理 - YF-海纳百川 - 博客园
6.2 持久化:
RDB机制:
save操作同步或者设置定时自动触发
在指定的时间间隔内生成数据集的时间点快照
(1)RDB文件紧凑,全量备份,非常适合用于进行备份和灾难恢复。
(2)生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。
(3)RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
一次全量备份,存储的是内存数据的二进制序列化形式,存储上非常紧凑,快照时父线程修改的数据可能无法保存
AOF机制:
修改时触发;异步,每秒触发;从不触发
持久化记录服务器执行的所有写操作命令
(1)可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据;
(2)AOF日志文件没有任何磁盘寻址的开销,写入性能非常高,文件不容易破损
(3)日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写
(4)AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复
Redis的两种持久化RDB和AOF(超详细)_鲨鱼辣椒灬的博客-CSDN博客_rdb和aof
https://baijiahao.baidu.com/s?id=1654694618189745916&wfr=spider&for=pc
6.3 缓存更新策略
内存溢出淘汰策略:
过期策略:过期;定时
Redis 缓存更新策略_爱与不爱,一念之间-CSDN博客_redis 更新策略
6.4 redis集群:
主从模式:master提供读写服务,写操作后同步内存到slave,slave只提供读服务,master挂掉停止写服务
哨兵模式:master挂掉后,会从其他slave选择新的master,每个sentinel以每秒钟一次的频率向它所知的master,slave以及其他sentinel实例发送一个 PING 命令
cluster模式:
7.hashMap
7.1 基本原理:
数组和链表的结合,解决修改和查找效率问题,对象entry(包含key,value),1.8后采用Node数组;
存储时:object.hasncode()获取hashcode(一般的Hash函数为:要存入的数 mod(求余) Hash数组长度),当hashcode相同时,存储在bucket链表的下一个节点;
取模:是(table.length - 1) & hash,算法直接舍弃了二进制hash值在table.length以上的位,因为那些位都代表table.length的2的n次方倍数。取模的结果就是Node将要放入table的下标。
获取值时:调用get(key)方法,通过键对象的hashcode找到bucket位置,再调用keys.equals()方法;
put()方法:第一次initTable()初始化table,长度是 16,计算hash找到位置,通过cas方法加入节点;如果table不为空,hash=i,table[i]为node,遍历链表查找是否有相同的hash值,如有相同hash值替换新的节点,如果没有直接插入新节点;table[i]为treenode,红黑树链表
扩容:懒加载机制(使用才加载),默认大小为16,负载因子大小为0.75,到达大小时进行rehashing过程,用散列扩容2倍,链表长度>8&&数组的长度>=64——转变为红黑树,根据hash值分为两个子链表;
equals结果为true的hashcode一定一样,为false的hashcode可能一样
7.2 如何减少hash碰撞:
使用String和Integer这wrapper类,尤其String类,final不可变,且重写了equals和hashcode()方法;
拉链法:目前hashmap使用的方法
rehash:哈希函数,二次哈希函数,,,
开放地址法:(h(key)+di) mod m(链表长度),di取值 1 2 3 ... m-1,线性探测再散列;di=1,每次冲突后后移一位,di=1 -1 2 -2 4 -4 9 -9 ...k*k -k*k(k<m/2),二次探测再散列;di取值可能为伪随机数列,称伪随机探测再散列
公共溢出区:记载冲突的点
负载因子调整
解决Hash碰撞冲突方法总结_lppl010_的专栏-CSDN博客_hash碰撞解决方法
7.3 线程安全问题
hashtable对比:
hasnhmap:元素无序,key可以为null, 线程不安全(Map m = Collections.synchronizeMap(hashMap);),效率高,
hashtable:元素有序,key不可为null, 线程安全(内部有synchronized),效率低
ConcurrentHashMap
1.初始化table:size标志位,yield(),cas放置Node
2.put()空节点null:cas,volatile
3.put()节点:cas,对当前节点sychronized
4.扩容:hash占位Node-1=MOVED,扩容时可参与帮助扩容
key不可为null,table数组元素作为锁,对每一行数据进行加锁,并发控制使用Synchronized和CAS来操作;
HashMap底层实现原理及面试问题_疯一样的女子-CSDN博客_hashmap底层实现原理
ConcurrentHashMap是如何实现线程安全的_|-| [- |_ |_ ()-CSDN博客_concurrenthashmap如何保证线程安全
HashMap的底层实现原理 - auldlangsynezh - 博客园
1.8的hashMap源码解析和红黑树
volatile V val; // get操作全程不需要加锁是因为Node的成员val是用volatile修饰
volatile Node<K,V> next; //Node<k,v>[] table,实现了Entry接口,表示链表中的下一个节点,数组用volatile修饰主要是保证在数组扩容的时候保证可见性;
setValue用final修饰
红黑树查找O(logn)
红黑树通过treemap(有序)实现
Java中HashMap底层实现原理(JDK1.8)源码分析_tuke_tuke的博客-CSDN博客_hashmap底层实现原理
7.4 JDK1.8的改动点:
1、JDK1.7版本锁的粒度是基于Segment的,包含多个HashEntry,而JDK1.8实现降低锁的粒度就是HashEntry(首节点)
2、JDK1.8版本的数据结构变得更加简单,去掉了Segment这种数据结构,使用synchronized来进行同步锁粒度降低,所以不需要分段锁的概念,实现的复杂度也增加了
3、JDK1.8使用红黑树来优化链表,基于长度很长的链表的遍历是一个很漫长的过程,而红黑树的遍历效率是很快的,代替一定阈值的链表,这样形成一个最佳拍档
4、JDK1.8为什么使用内置锁synchronized来代替重入锁ReentrantLock:
- 低粒度加锁方式,synchronized并不比ReentrantLock差,
粗粒度加锁中ReentrantLock可能通过Condition来控制各个低粒度的边界,更加的灵活,而在低粒度中,Condition的优势就没有了
- 在大量的数据操作下,对于JVM的内存压力,基于API的ReentrantLock会开销更多的内存
某个节点的hash值是MOVED,则表示正在进行数组扩张的数据复制阶段
ConcurrentHashMap实现原理及源码分析_快乐小石头的博客-CSDN博客_concurrenthashmap实现原理
7.5 扩容机制
Hashmap实现原理及扩容机制详解_lkforce-CSDN博客_hashmap扩容
8.设计模式
8.1 单例模式
1.单例类只有一个实例对象;
2.该单例对象必须由单例类自行创建;
3.单例类对外提供一个访问该单例的全局访问点。
懒汉式和饿汉式,包括线程安全和不安全的实现
8.1.1 懒汉式线程安全实现:
1.初始化变量用volatile修饰Singleton instance;(其中volatile作用是禁止指令重排序)
2.双重检验锁模式(double checked locking pattern):是一种使用同步块加锁的方法,称为双重检查锁,因为会有两次检查 instance == null,一次是在同步块外,一次是在同步块内;
8.1.2饿汉式线程安全实现方式:
1.初始化变量用final修饰
2.内部静态类
3.枚举
8.2.设计模式基础
设计原则:可复用,可扩展,可维护
开闭原则:对扩开放,对修改关闭;实现:抽象约束,封装变化
里式替换原则:继承必须确保超类所拥有的性质在子类中仍然成立
依赖倒置原则:要面向接口编程,不要面向实现编程。
8.3 工厂模式
静态工厂模式(简单工厂模式):通过向工厂传递类型来指定要创建的对象
一般工厂模式:抽象工厂,具体工厂,抽象产品,具体产品,将生产任务交给不同的派生类工厂。这样不用通过指定类型来创建对象了
抽象工厂模式:通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干
由于可能封装了大量对象和工厂创建,新加产品需要修改已定义好的工厂相关的类,因此对于产品和工厂的扩展不太友好
设计模式之工厂模式(factory pattern) - alpha_panda - 博客园
8.4 动态代理
代理模式:为其他类提供一个代理来控制对某个对象的访问,代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理
程序运行的过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2.创建被代理的类以及接口
3.通过Proxy的静态方法newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
4.通过代理调用方法
细说JDK动态代理的实现原理_痴人说梦-CSDN博客_jdk动态代理
Java JDK 动态代理(AOP)使用及实现原理分析_衣舞晨风-CSDN博客_jdk动态代理
10.ThreadLocal
ThreadLocal是JDK包提供的,它提供线程本地变量,在实际多线程操作的时候,操作的是自己本地内存中的变量——规避了线程安全问题;
两个本地变量inheritableThreadLocals和threadLocals,都是ThreadLocalMap类型的变量,使用完需要 remove(),否则可能一直存在弱引用,会导致内存溢出。
threadLocals不支持继承性,同一个ThreadLocal变量在父线程中被设置值后,在子线程中是获取不到的
inheritableThreadLocals子线程中可获取,重写了了childValue、getMap、createMap三个方法
弱引用:当一个线程调用ThreadLocal的set方法设置变量的时候,当前线程的ThreadLocalMap就会存放一个记录,这个记录的key值为ThreadLocal的弱引用
key是弱引用,所以当前线程的ThreadLocalMap里面的ThreadLocal变量的弱引用在gc的时候就被回收,但是对应的value还是存在的这就可能造成内存泄漏(因为这个时候ThreadLocalMap会存在key为null但是value不为null的entry项)
remove方法判断该当前线程对应的threadLocals变量是否为null,不为null就直接删除当前线程中指定的threadLocals变量
Java中的ThreadLocal详解 - CoderSheeper - 博客园