Table of Contents
源码分析ConcurrentLinkedQueue
ConcurrentLinkedQueue源码分析:https://www.cnblogs.com/zaizhoumo/p/7726218.html
深入研究java.lang.ThreadLocal
深入研究java.lang.ThreadLocal类: https://blog.csdn.net/c289054531/article/details/9187081
ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。
从线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种隔离机制。
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
mybatis相关知识
问题A:${}与#{}区别: #{} : 可以防止sql注入, sql语句在编译的过程中,会把值转换成?占位符, 在最终编译的时候,会对值进行转义,添加””, 当传入的值为简单数据类型的时候, 括号内部可以随便写 #{} ${} : 不能防止sql注入, 不会对传入的值进行转义的操作, 直接完成sql语句的拼接, 当传入的值为简单数据类型的时候, 括号内部必须写value ${value} PS: 当执行排序的sql语句的时候, order by , 后边必须写${} 问题B:resultType与resultMap区别: resultType: 语句返回值类型的整类名或别名。注意,如果是集合,那么这里填写的是集合的项的整类名或别名, 而不是集合本身的类名。(resultType 与resultMap 不能并用) resultMap 引用的外部resultMap 名。结果集映射是MyBatis 中最强大的特性。许多复杂的映射都可以轻松解决。 (resultType 与resultMap 不能并用)
分布式环境中的事务处理
spring boot面试题
redis和memcache, mongoDB的区别
Redis、Memcache和MongoDB的区别: https://www.cnblogs.com/tuyile006/p/6382062.html
Memcached的优点: Memcached可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS(取决于key、value的字节大小以及服务器硬件性能,日常环境中QPS高峰大约在4-6w左右)。适用于最大程度扛量。 支持直接配置为session handle。 Memcached的局限性: 只支持简单的key/value数据结构,不像Redis可以支持丰富的数据类型。 无法进行持久化,数据不能备份,只能用于缓存使用,且重启后数据全部丢失。 无法进行数据同步,不能将MC中的数据迁移到其他MC实例中。 Memcached内存分配采用Slab Allocation机制管理内存,value大小分布差异较大时会造成内存利用率降低,并引发低利用率时依然出现踢出等问题。需要用户注重value设计。 >>Redis Redis的优点: 支持多种数据结构,如 string(字符串)、 list(双向链表)、dict(hash表)、set(集合)、zset(排序set)、hyperloglog(基数估算) 支持持久化操作,可以进行aof及rdb数据持久化到磁盘,从而进行数据备份或数据恢复等操作,较好的防止数据丢失的手段。 支持通过Replication进行数据复制,通过master-slave机制,可以实时进行数据的同步复制,支持多级复制和增量复制,master-slave机制是Redis进行HA的重要手段。 单线程请求,所有命令串行执行,并发情况下不需要考虑数据一致性问题。 支持pub/sub消息订阅机制,可以用来进行消息订阅与通知。 支持简单的事务需求,但业界使用场景很少,并不成熟。 Redis的局限性: Redis只能使用单线程,性能受限于CPU性能,故单实例CPU最高才可能达到5-6wQPS每秒(取决于数据结构,数据大小以及服务器硬件性能,日常环境中QPS高峰大约在1-2w左右)。 支持简单的事务需求,但业界使用场景很少,并不成熟,既是优点也是缺点。 Redis在string类型上会消耗较多内存,可以使用dict(hash表)压缩存储以降低内存耗用。 Mc和Redis都是Key-Value类型,不适合在不同数据集之间建立关系,也不适合进行查询搜索。比如redis的keys pattern这种匹配操作,对redis的性能是灾难。
volatile修饰符, sychronized关键字, Lock类的区别
volatile、synchronized和lock解析: https://blog.csdn.net/ztchun/article/details/60778950
volatile是一个类型修饰符(type specifier)。它是被设计用来修饰被不同线程访问和修改的变量。 确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
什么是乐观锁
乐观锁 悲观锁 是一种思想。可以用在很多方面。
比如数据库方面。 悲观锁就是for update 乐观锁就是 version字段
JDK方面:
悲观锁就是synchronized
乐观锁就是原子类(内部使用CAS实现)
CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
本质来说,就是悲观锁认为总会有人抢我的。 乐观锁就认为,基本没人抢。
1 乐观锁,前提是不会发生并发抢占资源,只有在提交操作的时候检查是否违反数据完整性。只能防止脏读后数据的提交,不能解决脏读。 经典实现方式: 给表的增加一个字段:version每次的写操作更新version值 +1.然后每次读出来数据, 在写入数据库前,比较一下version是不是比读出来的大,如果是就更新,否则不更新。 (锁整条数据) 另外一种实现方式:(只锁某一条的某一个字段的值)先把 某一个子路的某一个字段取出来, 存到内存里,然后在写入的时候,同时把 内存里的值传入,看是否这个字段被改过,如果没有改过,继续写入,如果被改过,就放弃写入。
为什么spring默认是单例模式
spring的bean都是单实例(singleton)的,好处是:减少GC的频率,不要整天new一个对象出来, 然后不断被回收。同时单例模式已经能满足绝大部分业务需求了。单例模式是:线程无关性 通常我们弄的Bean都是无状态 + 单例的 所以才是能做到多线程安全的。 spring的scope 默认是单例模式, 同时默认是 饿汉模式的单例:启动容器时(即实例化容器时),为所有spring配置文件中定义的bean都生成一个实例 懒汉模式:在第一次请求是才生成一个实例,以后的请求直接调用这个实例。 <beans default-lazy-init="true"> <bean id="dvdTypeDAO" class="com.terana.hibernate.impl.DvdTypeDAOImpl" scope="prototype" /> 每次调用会new一个实例出来,
HashMap的长度为什么要是2的n次方
HashMap为了存取高效,要尽量较少碰撞,就是要尽量把数据分配均匀,每个链表长度大致相同,这个实现就在把数据存到哪个链表中的算法; 这个算法实际就是取模,hash%length,计算机中直接求余效率不如位移运算,源码中做了优化hash&(length-1), hash%length==hash&(length-1)的前提是length是2的n次
为什么这样能均匀分布减少碰撞呢?2的n次方实际就是1后面n个0,2的n次方-1 实际就是n个1; 例如长度为9时候,3&(9-1)=0 2&(9-1)=0 ,都在0上,碰撞了; 例如长度为8时候,3&(8-1)=3 2&(8-1)=2 ,不同位置上,不碰撞; 其实就是按位“与”的时候,每一位都能 &1 ,也就是和1111……1111111进行与运算