全网唯一一个从0开始帮助Java开发者转做大数据领域的公众号~
大数据技术与架构或者搜索import_bigdata关注~
海量【java和大数据的面试题+视频资料】整理在公众号,关注后可以下载~
List 元素是有序的、可重复
ArrayList、Vector默认初始容量为10
List 元素是有序的、可重复
ArrayList、Vector默认初始容量为10
Vector:线程安全,但速度慢
底层数据结构是数组结构
加载因子为1:即当 元素个数 超过 容量长度 时,进行扩容
扩容增量:原容量的 1倍
如 Vector的容量为10,一次扩容后是容量为20
ArrayList:线程不安全,查询速度快
底层数据结构是数组结构
扩容增量:原容量的 0.5倍+1
如 ArrayList的容量为10,一次扩容后是容量为16
Set(集) 元素无序的、不可重复。
HashSet:线程不安全,存取速度快
底层实现是一个HashMap(保存数据),实现Set接口
默认初始容量为16(为何是16,见下方对HashMap的描述)
加载因子为0.75:即当 元素个数 超过 容量长度的0.75倍 时,进行扩容
扩容增量:原容量的 1 倍
如 HashSet的容量为16,一次扩容后是容量为32
构造方法摘要HashSet()
HashSet(int initialCapacity)
构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。
HashSet hs=new HashSet(1);
所以可见 HashSet类,创建对象的时候是可以的制定容量的大小的 ,期中第二个就具有这个工功能。
Map是一个双列集合
HashMap:默认初始容量为16
(为何是16:16是2^4,可以提高查询效率,另外,32=16<<1 -->至于详细的原因可另行分析,或分析源代码)
加载因子为0.75:即当 元素个数 超过 容量长度的0.75倍 时,进行扩容
扩容增量:原容量的 1 倍
如 HashSet的容量为16,一次扩容后是容量为32
Hashtable: 线程安全
默认初始容量为11
加载因子为0.75:即当 元素个数 超过 容量长度的0.75倍 时,进行扩容
扩容增量:原容量的 1 倍+1
如 Hashtable的容量为11,一次扩容后是容量为23
###若hashcode方法永远返回1或者一个常量会产生什么结果?
首先,说一下这个“题目”中hashCode()返回常量1,重点在什么地方,重点在“常量”这两个字上,也就是说,每次使用java对象“.”hashCode()时,返回的都是相同的数值;
其次,说下hashCode()的值并不一定是对象在内存地址或物理地址,但是初学者可以这么理解;
第三,判断java对象的值是否相同的是equals方法,判断对象基本类型是否相同是用的==,而hashCode()这个方法也是比较对象是否相同的一个依据,
当hashCode()返回常量时,所有对象都出现hash冲突,而hashCode()本身的性能也会降级。
做hash的key的时候效率会极度变低。
变量比较也会变慢
java的Collections.sort算法调用的是合并排序,它是稳定排序,当数据接近有序的时候,效率更高collections中的数据在排序前需要输入到array中,接着调用Arrays.sort函数来完成对象排序,最近通过迭代器将数组中排好序的对象些人到collection中,这也要求collection必须为mutable类型的。
1.引用数法
引用计数法师垃圾收集的早期策略,在这中方法中,堆中每个对象都有一个引用计数,每当有一个地方引用他时,引用计数值就+1,当引用失效时,引用计数值就-1,任何时刻引用计数值为0的对象就是可以被回收,当一个对象被垃圾收集时,被它引用 的对象引用计数值就-1,所以在这种方法中一个对象被垃圾收集会导致后续其他对象的垃圾收集行动。
优点:判定效率高;
缺点:不完全准确,当两个对象相互引用的时候就无法回收,导致内存泄漏。
2.可达性分析算法
这个算法的基本思路就是通过一系列名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,下图对象object5, object6, object7虽然有互相判断,但它们到GC Roots是不可达的,所以它们将会判定为是可回收对象。
###String s="abc"和String s=new String(“abc”)区别;
String s=“abc”;这里不会在堆中创建对象,首先在常量池寻找这个常量“abc”,如果没有“abc”则把abc存放到运行时常量池,然后把引用赋值给是s,如果有就直接把存在的地址赋值给s。
String s=new String(“abc”);首先在堆中创建对象,然后再把对象引用赋值给s。
为什么需要重写equals和hashCode方法?
在我们的业务系统中判断对象时有时候需要的不是一种严格意义上的相等,而是一种业务上的对象相等。在这种情况下,原生的equals方法就不能满足我们的需求了
所以这个时候我们需要重写equals方法,来满足我们的业务系统上的需求。那么为什么在重写equals方法的时候需要重写hashCode方法呢?
我们先来看一下Object.hashCode的通用约定(摘自《Effective Java》第45页)
在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,那么,对该对象调用hashCode方法多次,它必须始终如一地返回 同一个整数。在同一个应用程序的多次执行过程中,这个整数可以不同,即这个应用程序这次执行返回的整数与下一次执行返回的整数可以不一致。
如果两个对象根据equals(Object)方法是相等的,那么调用这两个对象中任一个对象的hashCode方法必须产生同样的整数结果。
如果两个对象根据equals(Object)方法是不相等的,那么调用这两个对象中任一个对象的hashCode方法,不要求必须产生不同的整数结果。然而,程序员应该意识到这样的事实,对于不相等的对象产生截然不同的整数结果,有可能提高散列表(hash table)的性能。
如果只重写了equals方法而没有重写hashCode方法的话,则会违反约定的第二条:相等的对象必须具有相等的散列码(hashCode)。
同时对于HashSet和HashMap这些基于散列值(hash)实现的类。HashMap的底层处理机制是以数组的方法保存放入的数据的(Node[] table),其中的关键是数组下标的处理。数组的下标是根据传入的元素hashCode方法的返回值再和特定的值异或决定的。如果该数组位置上已经有放入的值了,且传入的键值相等则不处理,若不相等则覆盖原来的值,如果数组位置没有条目,则插入,并加入到相应的链表中。检查键是否存在也是根据hashCode值来确定的。所以如果不重写hashCode的话,可能导致HashSet、HashMap不能正常的运作、
如果我们将某个自定义对象存到HashMap或者HashSet及其类似实现类中的时候,如果该对象的属性参与了hashCode的计算,那么就不能修改该对象参数hashCode计算的属性了。有可能会移除不了元素,导致内存泄漏。
(1)概念
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
(2)功能
反射机制主要提供了以下功能:
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理
以上就是一个简单实现接口回调的机制,我们总结一下实现的所需的步骤:
1、定义回调接口和回调方法
2、Client实现回调接口和回调方法,并在Client中包含Service引用,通过引用调用Servie中的方法并且必须传入一个当前对象Client(因为当前对象实现了CallBack接口所以也属于接口对象)
3、在Service中定义一个接口对象并在方法中对初始化(将Client传过来的当前对象赋值给接口对象),通过接口对象调用接口中方法(调用的Client实现的接口方法)
4、测试
###AtomicInteger底层实现原理;
基于CAS的乐观锁实现
###synchronized与ReentraLock哪个是公平锁;
sychronized
在java中,每一个对象有且仅有一个同步锁。这也意味着,同步锁是依赖于对象而存在。
当我们调用某对象的synchronized方法时,就获取了该对象的同步锁。例如,synchronized(obj)就获取了“obj这个对象”的同步锁。
不同线程对同步锁的访问是互斥的。也就是说,某时间点,对象的同步锁只能被一个线程获取到!通过同步锁,我们就能在多线程中,实现对“对象/方法”的互斥访问。 例如,现在有两个线程A和线程B,它们都会访问“对象obj的同步锁”。假设,在某一时刻,线程A获取到“obj的同步锁”并在执行一些操作;而此时,线程B也企图获取“obj的同步锁” —— 线程B会获取失败,它必须等待,直到线程A释放了“该对象的同步锁”之后线程B才能获取到“obj的同步锁”从而才可以运行。
sychronized有三条原则:
CPU开销较大。在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很大的压力。
不能保证代码块的原子性。(只能保证单次操作的原子性)
ABA问题
抛出IllegalThreadStateException,线程的五种生命周期, 新建->就绪->运行->死亡->堵塞。在每次实例化的时候,会给这个threadStatus 为0,用volatile ,可以保证该变量的可见性。在不同的生命周期,值会变,而在start方法通过判断,就可以知道执行的线程是不是一个新的线程实例,
wait是Object中定义的方法,定义成final,是不能被重写的,你只能调用。一旦你调用了,就必须抛出或者捕获异常,但是可以被中断
https://blog.csdn.net/woshiluoye9/article/details/62038396
一.Executors: 提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService 接口。
ThreadPoolExecutor:线程池的具体实现类,一般用的各种线程池都是基于这个类实现的。
设置核心池的数量为 CPU 数的两倍,一般是 4、8,好点的 16 个线程
最大线程数设置为 64
空闲线程的存活时间设置为 1 秒
二.corePoolSize:线程池的核心线程数,线程池中运行的线程数也永远不会超过
corePoolSize 个,默认情况下可以一直存活。可以通过设置allowCoreThreadTimeOut为True,此时 核心线程数就是0,此时keepAliveTime控制所有线程的超时时间。
maximumPoolSize:线程池允许的最大线程数;
keepAliveTime: 指的是空闲线程结束的超时时间;
unit :是一个枚举,表示 keepAliveTime 的单位;
workQueue:表示存放任务的BlockingQueue BlockingQueue:阻塞队列(BlockingQueue)是java.util.concurrent下的主要用来控制线程同步的工具。如果BlockQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒。同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有空间才会被唤醒继续操作。 threadFactory:每个线程创建的地方 ,可以给线程起个好听的名字,设置个优先级啥的 handler:饱和策略,大家都很忙,咋办呢,有四种策略 CallerRunsPolicy:只要线程池没关闭,就直接用调用者所在线程来运行任务 AbortPolicy:直接抛出 RejectedExecutionException 异常 DiscardPolicy:悄悄把任务放生,不做了 DiscardOldestPolicy:把队列里待最久的那个任务扔了,然后再调用 execute() 试试看能行不 我们也可以实现自己的 RejectedExecutionHandler 接口自定义策略,比如如记录日志什么的 三.1.newFixedThreadPool 不招外包,有固定数量核心成员的正常互联网团队。 可以看到,FixedThreadPool 的核心线程数和最大线程数都是指定值,也就是说当线程池中的线程数超过核心线程数后,任务都会被放到阻塞队列中。 此外 keepAliveTime 为 0,也就是多余的空余线程会被立即终止(由于这里没有多余线程,这个参数也没什么意义了)。 而这里选用的阻塞队列是 LinkedBlockingQueue,使用的是默认容量 Integer.MAX_VALUE,相当于没有上限。 因此这个线程池执行任务的流程如下: 线程数少于核心线程数,也就是设置的线程数时,新建线程执行任务 由于队列容量非常大,可以一直加加加 2.newSingleThreadExecutor 线程池中没有线程时,新建一个线程执行任务 SingleThreadExecutor 用于串行执行任务的场景,每个任务必须按顺序执行,不需要并发执行。 3.newCachedThreadPool 全部外包,没活最多待 60 秒的外包团队。 可以看到,CachedThreadPool 没有核心线程,非核心线程数无上限,也就是全部使用外包,但是每个外包空闲的时间只有 60 秒,超过后就会被回收。 CachedThreadPool 使用的队列是 SynchronousQueue,这个队列的作用就是传递任务,并不会保存。 因此当提交任务的速度大于处理任务的速度时,每次提交一个任务,就会创建一个线程。极端情况下会创建过多的线程,耗尽 CPU 和内存资源。 它的执行流程如下: 没有核心线程,直接向 SynchronousQueue 中提交任务 CachedThreadPool 用于并发执行大量短期的小任务,或者是负载较轻的服务器。 4.newScheduledThreadPool 定期维护的 2B 业务团队,核心与外包成员都有。 ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor, 最多线程数为 Integer.MAX_VALUE ,使用 DelayedWorkQueue 作为任务队列。 ScheduledThreadPoolExecutor 添加任务和执行任务的机制与ThreadPoolExecutor 有所不同。 ScheduledThreadPoolExecutor 添加任务提供了另外两个方法: scheduleAtFixedRate() :按某种速率周期执行 当线程池中的核心线程数已满时,任务就要保存到队列中了。 线程池中使用的队列是 BlockingQueue 接口,常用的实现有如下几种: ArrayBlockingQueue:基于数组、有界,按 FIFO(先进先出)原则对元素进行排序 五.任务拒绝策略 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略: 1.ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 2.ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 3.ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程) 4.ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 六.线程池的关闭 ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown()和shutdownNow(),其中: shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务 避免一个线程同时获取多个锁。 Minor GC ,Full GC 触发条件 1、CMS收集器 3)CMS是一款“标记–清除”算法实现的收集器,容易出现大量空间碎片。当空间碎片过多,将会给大对象分配带来很大的麻烦,往往会出现老年代还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次Full GC。 Java内存泄漏引起的原因: https://blog.csdn.net/qq_27886997/article/details/78647877 BootStrap,ExtClassLoader,AppClassLoader Garbage First(G1)致力于在多CPU和大内存服务器上对垃圾收集提供软实时目标(soft real-time goal )和高吞吐量(high throughput )。从JDK 6u14开始就已经在Hotspot上试验,到现在的JDK7依然没有走出实验室。是最终将用于代替Concurrent Mark-Sweep garbage collector(CMS GC)的新一代垃圾回收器。目前JDK1.6update14及以后版本的jvm中已经继承了G1 GC,可以使用参数-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC来启用。G1是一个适用于服务器端、大内存、多CPU情景的垃圾收集器,主要目标是在维持高效率回收(high thoughput)的同时,提供软实时中断特性。用户可以指定一个时间上限,如果垃圾回收导致的程序暂停超过了用户设定的时间上限,会打断垃圾回收,恢复程序的执行。 根据经验贴一段设置 关于region: 在G1中,heap被平均分成若干个大小相等的区域(region)。每个region都有一个关联的remembered set (RS),RS的数据结构是hash table,里面的数据是card table (heap中每512byte映射在card table 1byte)。简单的说RS里面存在的是region中live objects的指针。当region中数据发生变化时,首先反映到card table中的一个或多个card上,RS通过扫描内部的card table得知region中内存使用情况和存活对象。 关于内存分配: 由于G1主要关注于多CPU多线程,所以内存分配采用 thread-local allocation buffers (TLABs)技术。每个分配线程都有一个自己的buffers用来分配对象,当buffers用完或者不够的时候,去重新申请一块内存放在自己的thread-local里面。这样对象的内存分配被最小化到私有的buffers里面,缓解了并发分配内存的压力。 当region被填满后,分配内存的线程会重新选择一个新的region。空region被组织到一个linked list里面,这样可以快速找到新的region。 对于大对象的分配不是在TLABs进行的,而是在TLABs之外。当一个对象的大小超过region的3/4的时候,这个对象被认为是巨大的(humongous )。巨大的对象被分配到特殊的区域(heap regions )。这些区域只包含巨大对象(humongous object )。 执行过程: ●初始标记 :Initial Marking ●并发标记 :Concurrent Marking ●最终标记 :Final Marking ●计数并清理 :Live Data Counting and Cleanup G1执行的第一阶段是初始标记(Initial Marking ),这个阶段是STW(Stop the World )的,所有mutator threads将被停止,标记出从GC Root开始直接可达的对象。然后,所有mutator threads将被重启,进入并发标记(Concurrent Marking )阶段。这个阶段从GC Root开始对heap中的对象标记,标记线程与应用程序线程并行直接,耗时较长。当并发标记完成后,开始最终标记(Final Marking )阶段。这个阶段主要是标记那些在并发标记阶段发生变化的对象。同样最终标记也要STW,但是多个标记线程并行运行,很快就可以完成。最后一个阶段会对每个区域(region)的回收成本和价值进行排序,根据用户指定的停顿时间,选择性的收集某些区域的对象,并统计每个区域对象的数量。 与CMS对比: 总体来说,G1跟CMS一样,是一块低延时的收集器,同样牺牲了吞吐量,不过二者之间得到了很好的权衡。 G1与CMS对比有一下不同: 1.分代: CMS中,堆被分为PermGen,YoungGen,OldGen;而YoungGen又分了两个survivo区域。在G1中,堆被平均分成几个区域(region),在每个区域中,虽然也保留了新老代的概念,但是收集器是以整个区域为单位收集的。 2.算法: 相对于CMS的“标记——清理”算法,G1会使用压缩算法,保证不产生多余的碎片。收集阶段,G1会将某个区域存活的对象拷贝的其他区域,然后将整个区域整个回收。 3.停顿时间可控: 为了缩短停顿时间,G1建立可预存停顿模型,这样在用户设置的停顿时间范围内,G1会选择适当的区域进行收集,确保停顿时间不超过用户指定时间 ###栈主要存的数据是什么,堆呢? ###软引用和弱引用的使用场景(软引用可以实现缓存,弱引用可以用来在回调函数中防止内存泄露); ###四、数据库 ###数据库索引,什么是全文索引,全文索引中的倒排索引是什么原理; ###数据库最佳左前缀原则是什么? ###数据库的三大范式; ###悲观锁和乐观锁的原理和应用场景; ###左连接、右连接、内连接、外连接、交叉连接、笛卡儿积等; ###一般情况下数据库宕机了如何进行恢复(什么是Write Ahead Log机制,什么是Double Write机制,什么是Check Point); ###什么是redo日志、什么是undo日志; ###关系型数据库和非关系型数据库区别; ###数据库死锁如何解决; ###MySQL并发情况下怎么解决(通过事务、隔离级别、锁); ###MySQL中的MVCC机制是什么意思,根据具体场景,MVCC是否有问题; ###MySQL数据库的隔离级别,以及如何解决幻读; ###Redis中zSet跳跃表问题; ###Redis的set的应用场合? ###Redis高级特性了解吗? ###Redis的pipeline有什么用处? ###Redis集群宕机如何处理,怎么样进行数据的迁移; ###Redis的集群方案; ###Redis原子操作怎么用比较好; ###Redis过期策略是怎么实现的呢? ###Spring中@Autowired和@Resource注解的区别? ###MyBatis有什么优势; ###MyBatis如何做事务管理; ###Linux静态链接和动态链接; 动态链接库的加载方式有两种:隐式加载和显示加载。 注意:linux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接(见本文第四部分)。 ###Linux中的grep管道用处?Linux的常用命令? ###操作系统中虚拟地址、逻辑地址、线性地址、物理地址的概念及区别; ###内存的页面置换算法; ###进程调度算法,操作系统是如何调度进程的; ###父子进程、孤儿进程、僵死进程等概念; ###fork进程时的操作; ###kill用法,某个进程杀不掉的原因(僵死进程;进入内核态,忽略kill信号); ###系统管理命令(如查看内存使用、网络情况); ###find命令、awk使用; ###Linux下排查某个死循环的线程; ###数据链路层是做什么的? ###数据链路层的流量控制? ###网络模型的分层、IP和Mac地址在那个层、TCP和HTTP分别在那个层; ###TCP滑动窗口; ###TCP为什么可靠; ###Https和Http有什么区别; ###Http 为什么是无状态的; ###TCP三次握手,为什么不是三次,为什么不是四次; ###TCP的拥塞控制、流量控制详细说明? ###Http1.0和Http2.0的区别; 每个请求都需单独建立连接(keep-alive能解决部分问题单不能交叉推送) 多路复用 ###地址解析协议ARP; ###OSI七层模型分别对应着五层模型的哪一部分; ###TCP三次握手数据丢失了怎么办?那如果后面又找到了呢? ###消息队列使用的场景介绍和作用(应用耦合、异步消息、流量削锋等); ###如何解决消息队列丢失消息和重复消费问题; ###Kafka使用过吗,什么是幂等性?怎么保证一致性,持久化怎么做,分区partition的理解,LEO是什么意思,如何保证多个partition之间数据一致性的(ISR机制),为什么Kafka可以这么快(基于磁盘的顺序读写); ###异步队列怎么实现; ###你项目的并发是多少?怎么解决高并发问题?单机情况下Tomcat的并发大概是多少,MySQL的并发大致是多少? ###什么是C10K问题; ###高并发情况下怎么办; ###分布式理论,什么是CAP理论,什么是Base理论,什么是Paxos理论; ###分布式协议的选举算法; ###说一下你对微服务的理解,与SOA的区别; ###Dubbo的基本原理,RPC,支持哪些通信方式,服务的调用过程; ###Dubbo如果有一个服务挂掉了怎么办; ###分布式系统中,每台机器如何产生一个唯一的随机值; ###系统的量级、pv、uv等; ###什么是Hash一致性算法?分布式缓存的一致性,服务器如何扩容(哈希环); ###正向代理、反向代理; ###什么是客户端负载均衡策略、什么是服务器端负载均衡策略; ###如何优化Tomcat,常见的优化方式有哪些; ###Nginx的Master和Worker,Nginx是如何处理请求的; ###十、系统设计相关 ###如何防止表单重复提交(Token令牌环等方式); ###有一个url白名单,需要使用正则表达式进行过滤,但是url量级很大,大概亿级,那么如何优化正则表达式?如何优化亿级的url匹配呢? ###常见的Nginx负载均衡策略;已有两台Nginx服务器了,倘若这时候再增加一台服务器,采用什么负载均衡算法比较好? ###扫描二维码登录的过程解析; ###如何设计一个生成唯一UUID的算法? ###实现一个负载均衡的算法,服务器资源分配为70%、20%、10%; ###有三个线程T1 T2 T3,如何保证他们按顺序执行; ###什么是XSS攻击,XSS攻击的一般表现形式有哪些?如何防止XSS攻击;
阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。具体的实现类有LinkedBlockingQueue,ArrayBlockingQueued等。一般其内部的都是通过Lock和Condition(显示锁(Lock)及Condition的学习与使用)来实现阻塞和唤醒。
线程数等于核心线程数后,将任务加入阻塞队列
执行完任务的线程反复去队列中取任务执行
FixedThreadPool 用于负载比较重的服务器,为了资源的合理利用,需要限制当前线程数量。
从参数可以看出来,SingleThreadExecutor 相当于特殊的 FixedThreadPool,它的执行流程如下:
有一个线程以后,将任务加入阻塞队列,不停加加加
唯一的这一个线程不停地去队列里取任务执行
听起来很可怜的样子 - -。
如果有空闲线程,就去取出任务执行;如果没有空闲线程,就新建一个
执行完任务的线程有 60 秒生存时间,如果在这个时间内可以接到新任务,就可以继续活下去,否则就拜拜
由于空闲 60 秒的线程会被终止,长时间保持空闲的 CachedThreadPool 不会占用任何资源。
scheduleWithFixedDelay():在某个延迟后执行
四。保存待执行任务的阻塞队列
LinkedBlockingQueue:基于链表,按FIFO (先进先出) 排序元素
吞吐量通常要高于 ArrayBlockingQueue
Executors.newFixedThreadPool() 使用了这个队列
SynchronousQueue:不存储元素的阻塞队列
每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态
吞吐量通常要高于 LinkedBlockingQueue
Executors.newCachedThreadPool使用了这个队列
PriorityBlockingQueue:具有优先级的、无限阻塞队列
shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务线程状态以及API怎么操作会发生这种转换;
常用的避免死锁方法;
避免一个线程在索内同时占用多个资源,尽量保证每个索只占用一个资源。
尝试使用定时索,使用 lock.tryLock(timeout) 来替代使用内部索机制。
对于数据库索,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。三、JVM
Minor GC与Full GC分别在什么时候发生?什么时候触发Full GC;
Minor GC触发条件:当Eden区满时,触发Minor GC。
Full GC触发条件:
(1)调用System.gc时,系统建议执行Full GC,但是不必然执行
(2)老年代空间不足
(3)方法去空间不足
(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存
(5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小GC收集器有哪些?CMS收集器与G1收集器的特点。
CMS收集器是一种以获取最短回收停顿时间为目标的收集器。基于“标记-清除”算法实现,它的运作过程如下:
1)初始标记
2)并发标记
3)重新标记
4)并发清除
初始标记、从新标记这两个步骤仍然需要“stop the world”,初始标记仅仅只是标记一下GC Roots能直接关联到的对象,熟读很快,并发标记阶段就是进行GC Roots Tracing,而重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生表动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长点,但远比并发标记的时间短。
CMS是一款优秀的收集器,主要优点:并发收集、低停顿。
缺点:
1)CMS收集器对CPU资源非常敏感。在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程而导致应用程序变慢,总吞吐量会降低。
2)CMS收集器无法处理浮动垃圾,可能会出现“Concurrent Mode Failure(并发模式故障)”失败而导致Full GC产生。
浮动垃圾:由于CMS并发清理阶段用户线程还在运行着,伴随着程序运行自然就会有新的垃圾不断产生,这部分垃圾出现的标记过程之后,CMS无法在当次收集中处理掉它们,只好留待下一次GC中再清理。这些垃圾就是“浮动垃圾”。
2、G1收集器
G1是一款面向服务端应用的垃圾收集器。G1具备如下特点:
1、并行于并发:G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短stop-The-World停顿时间。部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让java程序继续执行。
2、分代收集:虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念。它能够采用不同的方式去处理新创建的对象和已经存活了一段时间,熬过多次GC的旧对象以获取更好的收集效果。
3、空间整合:与CMS的“标记–清理”算法不同,G1从整体来看是基于“标记整理”算法实现的收集器;从局部上来看是基于“复制”算法实现的。
4、可预测的停顿:这是G1相对于CMS的另一个大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,
5、G1运作步骤:
1、初始标记;2、并发标记;3、最终标记;4、筛选回收
上面几个步骤的运作过程和CMS有很多相似之处。初始标记阶段仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS的值,让下一个阶段用户程序并发运行时,能在正确可用的Region中创建新对象,这一阶段需要停顿线程,但是耗时很短,并发标记阶段是从GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段时耗时较长,但可与用户程序并发执行。而最终标记阶段则是为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remenbered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,这一阶段需要停顿线程,但是可并行执行。最后在筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。Java在什么时候会出现内存泄漏;
内存泄漏是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费称为内存泄漏。
长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄漏,尽管短生命周期对象已经不再需要,但是因为长生命周期持有它的引用而导致不能被回收,这就是Java中内存泄漏的发生场景。
造成内存泄漏的几种情况:
1、静态集合类引起内存泄漏
像HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,他们所引用的所有的对象Object也不能被释放,因为他们也将一直被Vector等引用着。
2、当集合里面的对象属性被修改后,再调用remove()方法时不起作用。
3、监听器
在释放对象的时候却没有去删除这些监听器,增加了内存泄漏的机会。
4、各种连接
比如数据库连接(dataSourse.getConnection()),网络连接(socket)和io连接,除非其显式的调用了其close()方法将其连接关闭,否则是不会自动被GC 回收的。
5、内部类和外部模块的引用
内部类的引用是比较容易遗忘的一种,而且一旦没释放可能导致一系列的后继类对象没有释放。此外程序员还要小心外部模块不经意的引用,例如程序员A 负责A 模块,调用了B 模块的一个方法如: public void registerMsg(Object b); 这种调用就要非常小心了,传入了一个对象,很可能模块B就保持了对该对象的引用,这时候就需要注意模块B 是否提供相应的操作去除引用。
6、单例模式
不正确使用单例模式是引起内存泄漏的一个常见问题,单例对象在初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部的引用,那么这个对象将不能被JVM正常回收,导致内存泄漏。Java中的大对象如何进行存储;
rt.jar被什么类加载器加载,什么时间加载;
自己写的类被什么加载,什么时间加载;
自己写的两个不同的类是被同一个类加载器加载的吗?为什么?
为什么新生代内存需要有两个Survivor区?
几种常用的内存调试工具:jmap、jstack、jconsole;
类加载的五个过程:加载、验证、准备、解析、初始化;
G1停顿吗,CMS回收步骤,CMS为什么会停顿,停顿时间;
-server -verbose:gc -Xms10240m -Xmx10240 -XX:PermSize=128m -XX:MaxPermSize=128m -Xss256k -Xloggc: L O G H O M E / l o g s / g c . l o g − X X : + H e a p D u m p O n O u t O f M e m o r y E r r o r − X X : H e a p D u m p P a t h = {LOG_HOME}/logs/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath= LOGHOME/logs/gc.log−XX:+HeapDumpOnOutOfMemoryError−XX:HeapDumpPath={LOG_HOME}/logs/HeapDumpOnOutOfMemoryError.log -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:MaxGCPauseMillis=10 -XX:GCPauseIntervalMillis=200 -XX:+DisableExplicitGC -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
2.堆:存放使用new创建的对象,全局变量
###堆分为哪几块,比如说新生代老生代,那么新生代又分为什么?
Undo日志记录某数据被修改前的值,可以用来在事务失败时进行rollback;Redo日志记录某数据块被修改后的值,可以用来恢复未写入data file的已成功事务更新的数据
###数据库中的隔离性是怎样实现的;原子性、一致性、持久性又是如何实现的;
innodb通过undo log和redo log来实现。
锁
###什么是组合索引,组合索引什么时候会失效;
MySQL InnoDB事务的隔离级别有四级,默认是“可重复读”(REPEATABLE READ)。
· 未提交读(READUNCOMMITTED)。另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据(脏读)。
· 提交读(READCOMMITTED)。本事务读取到的是最新的数据(其他事务提交后的)。问题是,在同一个事务里,前后两次相同的SELECT会读到不同的结果(不重复读)。
· 可重复读(REPEATABLEREAD)。在同一个事务里,SELECT的结果是事务开始时时间点的状态,因此,同样的SELECT操作读到的结果会是一致的。但是,会有幻读现象(稍后解释)。
· 串行化(SERIALIZABLE)。读操作会隐式获取共享锁,可以保证不同事务间的互斥。
四个级别逐渐增强,每个级别解决一个问题。
· 脏读,最容易理解。另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据。
· 不重复读。解决了脏读后,会遇到,同一个事务执行过程中,另外一个事务提交了新数据,因此本事务先后两次读到的数据结果会不一致。
· 幻读。解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。但是,如果另一个事务同时提交了新数据,本事务再更新时,就会“惊奇的”发现了这些新数据,貌似之前读到的数据是“鬼影”一样的幻觉。
###五、缓存服务器
redis 实现事务的原理
https://blog.csdn.net/xiangnan129/article/details/54928672
###六、SSM相关
@Autowired默认按类型装配,@Resource(这个注解属于J2EE的),默认安照名称进行装配
###Spring声明一个 bean 如何对其进行个性化定制;
(1)使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交
(2)使用MANAGED的事务管理机制,这种机制mybatis自身不会去实现事务管理,而是让程序的容器(JBOSS,WebLogic)来实现对事务的管理
###七、操作系统
Linux下得库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀。面对比一下两者:
静态链接库:当要使用时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。
动态库而言:某个程序在运行中要调用某个动态链接库函数的时候,操作系统首先会查看所有正在运行的程序,看在内存里是否已有此库函数的拷贝了。如果有,则让其共享那一个拷贝;只有没有才链接载入。在程序运行的时候,被调用的动态链接库函数被安置在内存的某个地方,所有调用它的程序将指向这个代码段。因此,这些代码必须使用相对地址,而不是绝对地址。在编译的时候,我们需要告诉编译器,这些对象文件是用来做动态链接库的,所以要用地址无关代码(Position Independent Code (PIC))。
###什么是IO多路复用模型(select、poll、epoll);
FIFO LRU
###内存的页面置换算法;
top命令查看线程信息,接下来,我们用gdb来attach目标进程
###八、网络相关
3次握手四次挥手 确认和重传机制
###TCP的同传,拆包与组装包是什么意思;
HTTP1.0的缺陷
每个请求和响应都需要完整的头信息
数据未加密
HTTP2.0的优势
压缩头信息
请求划分优先级
支持服务器端主动推送
参考链接:
###两个不同ip地址的计算机之间如何通信;
当客户端收到服务端的SYN+ACK应答后,其状态变为ESTABLISHED,并会发送ACK包给服务端,准备发送数据了。如果此时ACK在网络中丢失,过了超时计时器后,那么Server端会重新发送SYN+ACK包,重传次数根据/proc/sys/net/ipv4/tcp_synack_retries来指定,默认是5次。如果重传指定次数到了后,仍然未收到ACK应答,那么一段时间后,Server自动关闭这个连接。但是Client认为这个连接已经建立,如果Client端向Server写数据,Server端将以RST包响应,方能感知到Server的错误。
当失败时服务器并不会重传ack报文,而是直接发送RTS报文段,进入CLOSED状态。这样做的目的是为了防止SYN洪泛攻击
###九、分布式相关
长连接 不重试 需要重启
###分布式事务,操作两个表不在一个库,如何保证一致性。
join countdownlatch
###三个线程循环输出ABCABCABC…
reentrantlock
###十一、安全相关