1.请介绍一下ThreadLocal底层是怎么实现的?
一个线程开始运行的时候,通过set方法会把值放入threadLocals这个变成中,他的类型是ThreadLocalMap对象,里面是Entry数组,每一个Entry是键值对形式,key就是ThreadLocal的引用,value就是我们set进去的值,这个数组的初始大小是16,达到阈值的时候会进行扩容(阈值=16*2/3)
2.ThreadLocal为什么会内存泄漏?
ThreadLocal是一个类似于HashMap的数据结构;
ThreadLocal的实现原理就是通过set把value set到线程的threadlocals属性中,threadlocals是一个Map,其中的key是ThreadLocal的this引用,value是我们所set的值;
如果一个线程执行完业务正常销毁,是不会产生内存泄露的,但是如果是一个线程池里的线程,在执行完业务后没有销毁而是回到了线程池中,就会产生内存泄漏,因为线程不销毁threadLocals就会存在,而他的类型TreadLocalMap就会存在,里面的Entry数组就存在以及他的每一个Entry键值对也存在,不断累积就会造成内存泄漏,其实底ThreadLocal底层有处理,就是每次set或get的时候key是空的,他就会把所有空的key的Entry给回收掉,但是建议在finally代码块中调用ThreadLocal的remove方法,这样可以避免内存泄漏。
3.请说说sleep()和wait()有什么区别?
wait()和sleep()方法都是Java中用于线程控制的方法,它们都让线程暂停执行,但它们之间存在一些区别:
1. 所属类和调用方式
wait()方法属于Object类,需要在synchronized块或方法中调用。
sleep()方法属于Thread类,可以在任何地方调用。
2. 对锁的处理机制
wait()方法会释放锁,让出CPU资源,并且线程进入等待状态,直到被其他线程唤醒。
sleep()方法不会释放锁,线程会一直占用CPU资源,只是暂停执行一段时间。
3. 唤醒机制
wait()方法需要被notify()或notifyAll()方法唤醒。
sleep()方法会自动苏醒,不需要其他线程唤醒。
4. 用途
wait()方法通常用于线程间通信和协作,例如生产者-消费者模型。
sleep()方法通常用于让线程暂停执行一段时间,例如模拟延迟操作。
5. 异常处理
wait()方法可能会抛出InterruptedException异常,需要捕获处理。
sleep()方法不会抛出异常。
6. 总结
①wait()方法和sleep()方法都让线程暂停执行,但wait()方法会释放锁,sleep()方法不会释放锁。
②wait()方法需要被notify()或notifyAll()方法唤醒,sleep()方法会自动苏醒。
③wait()方法通常用于线程间通信和协作,sleep()方法通常用于让线程暂停执行一段时间。
一些关于wait()和sleep()方法的常见问题①什么时候使用wait()方法?
当需要线程间通信和协作时,例如生产者-消费者模型。
当需要线程等待某个条件发生时,例如等待某个资源可用。②什么时候使用sleep()方法?
当需要让线程暂停执行一段时间时,例如模拟延迟操作。
当需要让线程休息一下,避免CPU资源过度消耗时。③wait()方法和sleep()方法哪个更好?
如果需要线程间通信和协作,则应该使用wait()方法。
如果只是需要让线程暂停执行一段时间,则可以使用sleep()方法。
4.多个线程如何保证按顺序执行?
1、通过join()方法使当前线程“阻塞”,等待指定线程执行完毕后继续执行;
2、通过创建单一化线程池newSingleThreadExecutor()实现;
3、通过倒数计时器CountDownLatch实现;
4、使用Object的wait/notify方法实现;
5、使用线程的Condition(条件变量)方法实现;
6、使用线程的CyclicBarrier(回环栅栏)方法实现;
7、使用线程的Semaphore(信号量)方法实现;
5.Java线程池中submit()和execute()方法有什么区别?
(1) 两个方法都可以向线程池提交任务;
(2) execute只能提交Runnable,无返回值;
(3) submit既可以提交Runnable,返回值为null,也可以提交Callable,返回值Future;
(4) execute()方法定义在Executor接口中;
(5) submit()方法定义在ExecutorService接口中;
(6) execute执行任务时遇到异常会直接抛出;
(7) submit执行任务时遇到异常不会直接抛出,只有在调用Future的get()方法获取返回值时,才会抛出异常;