面试必备系列-Java基础相关(二)
java是引用传递还是值传递
引用知乎的一位大神的理解,讲的很到位。
https://www.zhihu.com/question/31203609
ThreadLocal为什么会内存泄露
ThreadLocal我们通常会用在一个线程里面共享一个变量,通过ThreadLocal.set()
方法将变量数据放进去。
1public void set(T value) {
2 // 获取当前线程
3 Thread t = Thread.currentThread();
4 // 获取ThreadLocalMap
5 ThreadLocalMap map = getMap(t);
6 if (map != null)
7 // 不为空,则放入进去
8 map.set(this, value);
9 else
10 // 为空,则创建一个ThreadLocalMap,然后将值放进去
11 createMap(t, value);
12}
每个Thread 中都有个ThreadLocalMap, 这个MAP中key为ThreadLocal ,value为存储的值。 其中key为弱引用。
弱引用的定义: 如果外部没有强引用对他引用,那么他将在最近的一次GC被回收。
所以在ThreadLocal外部引用他的对象被回收了,那么ThreadLocal也将被回收, 这就导致了ThreadLocalMap中
存在key的引用为null, 但是value不为空的情况。
针对上面那种情况,ThreadLocalMap在下次set ,get,remove的时候,会自动清除掉key为null的value。
内存泄露的原因:
ThreadLocalMap中存在大量key为null的value,但是线程一直无法结束,同时也没有继续调用get,set,remove
方法,这就导致了map中有大量的value无法被清除。 因此导致内存泄露。 泄露的根本原因是因为ThreadLocalMap的生命周期和Thread一致。 如过Thread短时间不结束。那么ThreadLocalMap也不会被回收。
JVM针对这种情况做出的优化:
1.ThreadLocalMap的key(ThreadLocal)采用弱引用,因此在使用ThreadLocal的对象被回收,key在下次GC也会被回收
2.在ThreadLocalMap get,set ,remove的会清除掉key为null的value
通过以上两个机制,JVM尽可能的保证不发生内存泄露,但是做不到根治。
Rentrantlock和synchronized的区别
synchronized是JVM的实现 , 发生异常时,JVM会自动释放锁,JDK1.6之前性能较差,1.6之后,synchronized也
采用了CAS的操作,性能大幅度提高。
Rentrantlock是基于AQS实现的,lock()之后必须在finallylim调用unlock() , 提供了更多的API,可以完成更多的功能,比如tryLock()尝试获取锁,如果获取不到锁则不必继续等待。 同时提供了公平锁和非公平锁的选择。
详情可以看: https://blog.csdn.net/u012394095/article/details/80518594
synchronized相关问题
1public class Demo1 {
2 public synchronized static void add(){
3 System.out.println("add");
4 }
5 public static void edit(){
6 synchronized (Demo1.class){
7 System.out.println("edit");
8 }
9 }
10}
如上所示,add方法和edit方法能够做到互斥吗?
答案是可以的,静态方法上加synchronized,锁住的就是Demo1这个class对象。
ThreadPoolExecutor几个参数的作用
1corePoolSize : 核心线程池大小
2maximumPoolSize : 最大线程数量
3keepAliveTime : 超出核心线程池大小的线程过多少时间回收
4unit : keepAliveTime的单位
5workQueue : 当核心线程池已经满了的并且没有空闲的线程时,任务放入到队列中
6threadFactory : 产生线程的工厂,我们可以自定义,比如说,对线程命名,根据一定的规则产生
7同时可以设定线程是否是守护线程
8RejectedExecutionHandler : 当队列满了,最大线程数也满了,那么就要根据拒绝策略来决定任务的去留
ThreadPoolExecutor的拒绝策略
AbortPolicy : 直接拒绝,报异常
CallerRunsPolicy : 直接在execute方法中调用线程的run方法,如果线程池已经关闭,则丢弃该任务
DiscardOldestPolicy : 丢弃最早的那个任务,也就是队列中的第一个任务,然后重新调用execute方法
DiscardPolicy : 直接丢弃,不做任何处理
上一篇: java集合框架、面试