Java面试特殊知识点总结 part1

2021-02-04 10:33:11 浏览数 (1)

并发与多线程

main方法里没有创建新的线程,执行main方法一共需要几个线程?

可以使用ManagementFactorygetThreadMXBean方法获取ThreadMXBean信息,进而获取线程信息进行查看。代码:

代码语言:javascript复制
package Exercise;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

public class Test {
    public static void main(String[] args) {
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);

        for (ThreadInfo threadInfo : threadInfos) {
            System.out.println(threadInfo.getThreadId()   ":"   threadInfo.getThreadName());
        }
    }
}

运行结果:

代码语言:javascript复制
6:Monitor Ctrl-Break
5:Attach Listener
4:Signal Dispatcher
3:Finalizer
2:Reference Handler
1:main

答案是6个,通过每个线程的名字可以知道他们的作用。

ThreadLocal

ThreadLocal为每个线程创建一个变量的副本,对彼此不可见,它基于ThreadLocalMap实现。

核心机制如下:

  1. 每个Thread线程内部都有一个map(ThreadLocalMap)。
  2. map里面存储线程本地对象key和线程变量副本value
  3. Thread内部的map是由ThreadLocal维护的,由ThreadLocal负责向map获取和设置线程的变量值。

每个线程只能获取自己的副本值,不能获取其他线程的,这样就形成了隔离,互不干扰。

ThreadLocal类提供了以下几个核心方法:

1.get()方法:获取当前线程的副本变量值。 2.set()方法:设置当前线程的副本变量值。 3.remove()方法:移除当前线程的副本变量值。 4.initilaValue()方法:初始化当前线程的副本变量值,初始化为null

ThreadLocalMapThreadLocal内部的一个map实现, 它和HashMap实现自Map接口不一样,它没有实现任何接口,仅供ThreadLocal内部使用,数据结构采用数组加开放地址法,Entry继承自WeakReference,是基于ThreadLocal场景下实现的特殊Map,源码见参考文献第一篇。

ThreadLocal的应用场景:
  1. 在对象进行跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。
  2. 线程间数据隔离。
  3. 进行事务操作,用于存储事务信息。
  4. ·数据库连接,Session会话管理。

发生了死锁,如何排查

使用jps获取发生死锁的进程号。 使用jstack 进程号查看该进程堆栈,它会详细显示死锁数量,相关联的线程,发生死锁的大致代码位置等信息。

jconsole也可以查看相关信息。

黑名单功能如何实现

使用写时复制容器CopyOnWriteArrayList实现。

什么是写时复制容器

写时复制是指,在并发访问的场景下,需要修改Java中容器中的元素时,不直接修改该容器中,而是先复制一份副本,在副本上进行修改。修改完成之后,将指向原来容器的引用指向新的副本容器。

写时复制带来的影响
  1. 由于不会修改原始容器,只修改副本容器,可以对原始容器进行并发地读。其次,实现了读操作和写操作的分离:读操作发生在原始容器上,写操作发生在副本容器上。
  2. 数据一致性问题:读操作的线程可能不会立即读取到新修改的数据,因为修改操作可能会发生在副本上,但最终修改操作会完成并更新容器,因此只能保证最终一致性。
写时复制容器

JDK中提供了CopyOnWriteArrayListCopyOnWriteArraySet类,但是没有提供CopyOnWriteHashMap,可以自己实现一个。

写时复制容器适用的场景

CopyOnWrite容器适用于读多写少的场景。因为写操作时,需要复制一个容器,造成内存开销很大,也需要根据实际应用把握初始容器的大小。

不适合数据的强一致性场合。若要求数据修改之后能立即被读到,则不能使用写时复制技术,因为它只能保证最终一致性。

参考文献

深入源码理解ThreadLocal和ThreadLocalMap

面试官:知道ThreadLocal嘛?谈谈你对它的理解?(基于jdk1.8)

JAVA中写时复制(Copy-On-Write)Map实现

0 人点赞