B站面试Java基础ArrayList和LinkedList的区别?ArrayList是基于动态数组实现的,LinedList是基于链表结构实现的。对于随机访问,ArrayList优先于Linkedist。LinkedList需要移动指针。对于插入和删除数据的LinkedList只需要改变前后的指针引用即可。ArrayList需要移动插入/删除的元素,比较耗时。AQS简单介绍一些常用的技术(ReentrantLock)AQS(AbstracyQueueSynchronizer)抽象队列同步器state(int)Queue(null)主要实现原理涉及两个参数扩展:Synchronized和ReentrantLock的区别?同步锁转换,偏向锁(无锁->偏向锁->轻量级锁->重量级锁)?synchronized是Java关键字,是JVM级别的锁。它是通过代码块/方法中的notify/wait来实现的。ReentrantLock是一个jdk原生的锁。底层原理是CAS是否可以手动释放:Synchronized不能手动释放锁,必须在代码块/方法执行完成后才能释放锁。ReentrantLock如果忘记释放锁,就会一直持有锁,造成死锁。所以释放锁的操作一般放在finally中执行releaseunlock()操作。是否可中断:Synchronized是不可中断锁,必须是线程执行完成/代码中出现异常。ReentrantLock可以被中断。TryLock(timeout,TimeUnit)设置超时方法或将lockInterruptibly()放在代码块中。中断调用interrupt方法是否公平:synchronized是非公平锁。ReentrantLock可以选择公平锁或者非公平锁。公平锁,在构造newReentrantLock时通过传入boolean值来选择,如果为空,则默认为false和非公平锁,true是公平锁锁唤醒的准确性:synchronized不能绑定;ReentrantLock通过绑定Condition结合await()/singal()方法实现了线程的精准唤醒,而不是通过wait()/notify()/notifyAll()随机唤醒一个线程或者唤醒所有线程Object类的方法,如同步。锁的对象:synchronzied锁是对象,锁保存在对象头中,根据对象头数据识别是否有线程获取锁/竞争锁;ReentrantLock锁是线程,根据传入的线程和int类型状态如何获取/竞争多线程来识别锁?(介绍线程池的使用和一些核心参数以及如何设置线程数)多线程一般使用ThreadPoolExecutor创建自定义线程池,线程池参数coreSize:核心线程数maxSize:最大线程数time:longesttimeacorethreadsurvivedtimeUnit:生存时间单位queue:存放新任务的队列abortPolicy:拒绝策略factory:创建线程的自定义工厂线程的创建数量一般根据线程的性质决定线程数量的配置业务,一般是CPU-intensive/IO-intensive类型,一般是按照这个公式计算:线程数=[(线程等待时间+线程处理时间)/线程处理时间]Ncpu数,IO耗时CPU密集型线程的等待阻塞时间基本为0,即计算结果为Ncpu数,IO密集型线程等待阻塞时间为线程处理时间的倍数,假设等待时间等于处理时间,即Spring中2Ncpu常用设计模式介绍?(代理模式、工厂模式、单例模式)代理模式:AOP切面(JDK动态代理模式&CGlib代理模式)工厂模式:FactoryBean(定义创建工厂的接口,对象的创建和实例化由工厂实现)单例模式:保证只有一个bean被实例化,可以通过singleton="true|false"或者scope="?"来指定观察者模式:一对多的依赖关系。当一个对象的状态发生变化时,所有依赖它的对象都会收到通知并自动更新。spring中观察者模式最常见的用法就是监听器的实现。比如ApplicationListener策略模式:定义一系列的算法,一个一个封装起来,让它们可以互换。此模式使算法能够独立于使用它的客户端进行更改。volatile和final关键字volatilefinal(可以修饰类、方法、变量)final修饰的类:那么这个类不能被继承,这个类中的所有方法都是隐式的会变成final修饰方法:那么这个方法就不能被子类重写了。需要注意的一点是:因为重写的前提是子类可以继承父类的这个方法,如果同时访问父类中final修改的方法控制权限是私有的,会导致不能直接继承此方法的子类。因此,此时可以在子类中定义相同的方法名和参数。这时候rewriting和final就不会再有矛盾了,而是在子类的类中重新定义了一个新的方法。(注意:类的私有方法会被隐式指定为final方法。final修饰的变量:只能赋值一次,赋值后不会改变。当final修饰一个基本数据类型时,意味着基本数据类型一旦初始化后就不能再改变;如果final修饰了一个引用类型,它初始化后就不能再指向其他对象,但是引用指向的对象的内容是可以改变的。本质上是一样的东西,因为引用的值是一个地址,所以final需要一个值,即地址的值不变。final修饰一个成员变量(属性),必须显式初始化。这里有两种初始化方式,一种是在变量在声明的时候初始化;第二种方法是在声明变量的时候不赋初值,而是在变量所在类的所有构造函数中给这个变量赋初值。当函数的参数类型为声明为final,表示该参数是只读的。也就是说,您可以读取和使用该参数,但不能更改该参数的值。ThreadLocal的使用,以及注意点?为什么内存泄漏?ThreadLocal防止在多线程的情况下对同一个变量进行操作。每个线程都有自己的局部变量进行操作,互不影响。ThreadLocal的存储方式类似于Map结构key和value,存储set,取值get,删除remove,key当前线程引用ThreadLocal的key是软引用,因为ThreadLcoal的存储结构是Entry,而Entry继承了WeakReference>。存储数据时,新建实例Entry,存储的key是弱引用。这样就会导致内存溢出的问题。当内存不足时,JVM会进行GC,GC会回收软引用,然后key会被回收,value会一直存在,这样会导致内存不断膨胀却无法回收。.所以在使用ThreadLocal的时候,一定要在使用完之后的finally块中移除。Java中的对象引用有哪些类型?强引用(StrongReference)最强大的一般是新建实例对象软引用(SoftReference)它的作用是告诉垃圾回收器程序中哪些对象不是那么重要,可以在内存不足时临时回收的。当JVM中的内存不足时,垃圾回收器会释放那些只被软引用指向的对象。如果释放所有这些对象后内存不足,则会抛出OutOfMemory错误。软引用非常适合创建缓存。当系统内存不足时,缓存中的内容是可以释放的弱引用(WeakReferene)。它的作用是引用一个对象,但不妨碍对象被回收。如果使用强引用,只要引用存在,被引用的对象就不能被回收。弱引用没有这个问题。当垃圾收集器运行时,如果对一个对象的所有引用都是弱引用,则该对象将被回收。弱引用的作用是解决强引用带来的对象间在生存时间上的耦合关系。弱引用最常见的用途是在集合类中,尤其是在哈希表中。Hashtable接口允许将任何Java对象用作键。当一个键值对被放入哈希表时,哈希表对象本身就有对这些键值对象的引用。如果这种引用是强引用,那么只要哈希表对象本身还活着,其中包含的key和value对象就不会被回收。如果一个长期存在的哈希表包含许多键值对,它最终可能会耗尽JVM中的所有内存。幻影引用(PhantomReference)在Object类中有一个finalize方法,其初衷是在一个对象真正被回收之前,可以用来进行一些清理工作。因为Java没有提供和C++的析构函数一样的机制,所以是通过finalize方法来实现的。但问题是垃圾收集器的运行时间是不固定的,所以这些清理任务的实际运行时间也是不可预测的。幻象引用可以解决这个问题。创建PhantomReference时必须指定引用队列。当一个对象的finalize方法被调用时,对该对象的幽灵引用被排队。通过检查队列的内容,可以知道一个对象是否准备好被回收。程序可以通过判断引用队列中是否加入了幻象引用来获知被引用对象是否即将被垃圾回收。如果程序发现引用队列中加入了虚引用,则可以在被引用对象的内存被回收之前采取必要的动作。ConcurrentHashMap和Map的区别以及ConcurrentHashMap的实现原理?多路复用IO的原理?中间件redis的基本数据结构?String、Set、SortedSet、Map、ListRedis基本数据类型结合具体场景?购物车的实现采用什么数据结构类型?--地图实现随机抽取3名获胜者?--set,使用set的pop命令实现前3名的排名?--SortedSet的ZRang命令取前3个值,取一个人的共同好友?--set,为什么使用set的union命令redis快?单线程,无线程上下文切换内存操作多路复用IO模型Redis实现分布式锁?redis实现分布式锁的方式是setnx命令,即多个线程并发时设置同一个key的值。当其他线程抢占锁时,会发现key已经有值了,就会放弃抢占锁。redis操作的分布式锁的实现会遇到很多坑:一个线程在setnx之后一直在处理业务,没有释放锁,会导致其他线程等待,得不到锁,这样线程池就会满,所以在设置锁的时候,线程需要加上锁的超时时间。当锁的执行超过超时时间,就会主动释放锁。一个线程在执行过程中在指定超时时间内完成业务处理,发送del命令释放锁,但是由于系统负载/网络原因,该命令没有发送成功。当超时到期时,锁会自动释放。然后B线程拿到锁,B线程在处理中。这时A的命令重试成功删除了锁,那么B就会出现不可预知的错误。所以我们在del的时候,首先要拿到key对应的value。value的值不能是唯一的,这样会误删锁,get和del的操作必须是原子的(Lua脚本写的,lua脚本就是一行操作命令,不管有多少开头和结尾之间的操作,它们是一次性执行的)zookeeper和eureka有什么区别?使用注册表的优点和缺点?两者都是先实现服务注册的中间件CAP理论:C:一致性A:可用性P:分区容错zookeeper在CAP理论中只能保证CP,一致性不一定是强一致性而是最终一致性P分区的容错类型是集群的高可用性。这是分布式系统的基础。由于zk的选举机制,zk的集群会不可用,当zkmaster挂掉,进行选举时,整个集群不可用。这在分布式系统中是致命的。数据不一致可以容忍,但不能不管系统业务如何(当master节点由于网络故障与其他节点失去联系时,其余节点会重新选举leader。问题是,选举leader时间过长,30~120s,选举时整个zk集群不可用,导致选举时注册服务瘫痪)。Eureka保证CAP中的AP:P不说这是基础,C不是强一致性保证最终一致性,A:Availability,Eureka也有自我保护机制,如果15分钟内超过85%的话所有节点都没有正常的心跳,则Eureka认为客户端与注册中心之间存在网络故障:1.Eureka不再从注册列表中移除因长时间未收到心跳而应该过期的服务。2、Eureka仍然可以接受新服务的注册和查询请求,但不会同步到其他节点(即保证当前节点仍然可用)3、当网络稳定时,新服务的注册信息当前实例会被同步到其他节点(Eureka有客户端Caching技术:Eureka分为客户端程序和服务端程序两部分,客户端程序负责对外提供注册和发现服务接口)。所以即使Eureka集群中所有节点都失效,或者出现网段故障,客户端也无法访问任何Eureka服务器;Eureka服务的消费者仍然可以通过Eureka客户端缓存获取已有的服务注册信息。即使在最极端的环境下,所有正常的Eureka节点都不响应请求,目前还没有更好的服务器方案来解决这个问题;得益于Eureka的客户端缓存技术,消费者服务依然可以通过EurekaClient查询获取注册服务信息)zookeeper实现分布式锁?首先,zk有四种节点类型:持久节点、持久时序节点、临时节点、临时时序节点。zk实现了分布式锁节点,利用临时时序节点的特性来实现zk的分布式锁。持久节点用作根节点。在该节点下创建一个新的临时顺序节点。例如Client-A在该目录下新建一个/root/lock1节点,Client-B在该目录下新建一个/root/lock2节点。所有的节点都是顺序递增的,所以在客户端获取锁的时候判断你的节点是否是当前节点集合中最小的节点,如果是就获取锁,如果不是就在当前节点上面的节点添加一个watcher监听lock1节点是否存在,而CLient-C会监听lock2,切记不要监听第一个如果一个节点监听第一个节点,当节点被删除时,所有临时节点都会收到这个消息,多个节点会同时竞争锁(羊群效应)。当发生变化时,ZooKeeper会触发一个由特定znode节点的变化引起的所有watchpoints的集合。如果1000个clients通过exists操作监控这个znode节点,那么在创建znode节点的时候会发送1000个通知,所以被监控的znode节点发生变化会产生一个spike通知,这可能会产生影响,比如delayin在高峰时段提交的操作。如果可能,我们建议在使用ZooKeeper时,避免在特定节点上设置大量观察点。最好一次只在特定的znode节点上设置观察点。只有少数客户,理想情况下最多只有一个。消息重复消费如何处理?消息实现分布式事务?数据库Mysql使用的引擎是什么?有什么不同?InnerDB/MySlamDBMySlam:不支持事务也不支持外键,不支持行级锁,只支持并发插入的表锁,MyISAM也使用B+树索引但在具体实现上与Innodb有些区别(优缺点:MyISAM优点是占用空间小,处理速度快,缺点是不支持事务完整性和并发)InnerDB支持事务,提供自增列,支持外键。指出MVCC行级锁支持的索引类型是B+树(InnoDB的优点是提供了良好的事务处理、崩溃恢复能力和并发控制。缺点是读写效率差,占用的数据空间比较大)Mysql中索引的数据结构是什么?B+树和Hash索引有什么区别?InnerDB使用B+数结构Mysql索引失效与最左匹配原则?mysql查询优化器会以最高效率判断并修正SQL语句应该执行的顺序,最终生成真正的执行计划。所以,当然,我们能尽量使用索引时的查询顺序是最高效的,所以mysql查询优化器最终会按照这个顺序执行查询。解释select*fromtestwhereb<10andc<10;解释select*fromtestwherea<10andc<10;为什么b<10和c<10,没有使用索引?而a<10和c<10是用的吗?当b+树的数据项为复合数据结构时,如(name,age,sex),b+数是从左到右依次构建搜索树,如(a,b,c)时数据检索出来后,b+树会先比较名字来决定下一步的查找方向。如果姓名相同,则依次比较年龄和性别,最后得到检索到的数据;但是当(b,c)没有name数据来的时候,b+树不知道接下来要查哪个节点,因为name是建搜索树时的第一个比较因素,必须先根据name进行搜索知道下一步在哪里查询。比如在检索(a,c)这样的数据时,b+树可以使用name来指定查找方向,但是缺少了下一个字段age,所以只能找到name等于张三的所有数据,然后匹配性别为F的数据,这是一个很重要的属性,即索引的最左匹配特征。扩展到ACID的实现原理?数据库的隔离级别?数据库乐观锁?ACID:A(原子性):一个事务中的多个操作要么成功要么失败C(一致性):一个事务执行前后,必须保证从一种一致状态变为另一种一致状态。例如:A和B共有400元。A和B来回转移。不管转多少次,最后的结果都是A和B合计400元。I(Isolation):一个事务的运行不同于其他事务的运行。D(持久性)互不影响,相互隔离:提交一个事务。如果提交成功,数据必须永久保存。即使系统出现故障,恢复后数据应该仍然存在。隔离级别Readuncommitted:没有读到的Committed:可以避免脏读Repeatablereads:可以避免脏读,不可重复读,这是Mysql默认的隔离级别Serialization:可以避免脏读,不可重复读,幻像Readoracle只有两个隔离级别:readcommitted(默认)和serialized。脏读:指一个事务正在访问数据,修改了数据,而这个数据还没有提交到数据库。这时,另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据还没有提交,所以被另一个事务读到的数据就叫做脏数据。基于脏数据的操作可能是错误的。不可重复读:指在一个事务中多次读取同一个数据。在这个事务执行结束之前,另一个事务也访问了相同的数据,那么在第一个事务的两次读取数据之间,由于第二个事务的修改,第一个事务两次读取的数据可能不一样,这样在一个事务中连续读取两次的数据是不同的。这种情况称为不可重复读。幻读:一个事务连续读取一个范围内的记录,但是两次读取的记录数不一样,我们称之为幻读(两次执行同??一个select语句会得到不同的结果,第二次读取会增加一条数据行并没有说两次执行是在同一个事务中。数据结构红黑数和平衡二叉树的区别?红黑树最长路径和最短路径的关系?扩展--TheMap数据结构的变化是由之前的链表结构决定的-->红黑树的转换?