可以使用ManagementFactory
的getThreadMXBean
方法获取ThreadMXBean
信息,进而获取线程信息进行查看。代码:
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());
}
}
}
运行结果:
6:Monitor Ctrl-Break
5:Attach Listener
4:Signal Dispatcher
3:Finalizer
2:Reference Handler
1:main
答案是6个,通过每个线程的名字可以知道他们的作用。
ThreadLocal
为每个线程创建一个变量的副本,对彼此不可见,它基于ThreadLocalMap
实现。
核心机制如下:
map
(ThreadLocalMap)。key
和线程变量副本value
。map
是由ThreadLocal
维护的,由ThreadLocal
负责向map
获取和设置线程的变量值。每个线程只能获取自己的副本值,不能获取其他线程的,这样就形成了隔离,互不干扰。
1.get()
方法:获取当前线程的副本变量值。
2.set()
方法:设置当前线程的副本变量值。
3.remove()
方法:移除当前线程的副本变量值。
4.initilaValue()
方法:初始化当前线程的副本变量值,初始化为null
。
ThreadLocalMap
是ThreadLocal
内部的一个map实现,
它和HashMap
实现自Map
接口不一样,它没有实现任何接口,仅供ThreadLocal
内部使用,数据结构采用数组加开放地址法,Entry
继承自WeakReference
,是基于ThreadLocal
场景下实现的特殊Map,源码见参考文献第一篇。
使用jps
获取发生死锁的进程号。
使用jstack
+进程号查看该进程堆栈,它会详细显示死锁数量,相关联的线程,发生死锁的大致代码位置等信息。
jconsole
也可以查看相关信息。
使用写时复制容器CopyOnWriteArrayList
实现。
写时复制是指,在并发访问的场景下,需要修改Java中容器中的元素时,不直接修改该容器中,而是先复制一份副本,在副本上进行修改。修改完成之后,将指向原来容器的引用指向新的副本容器。
JDK中提供了CopyOnWriteArrayList
和CopyOnWriteArraySet
类,但是没有提供CopyOnWriteHashMap,可以自己实现一个。
CopyOnWrite容器适用于读多写少的场景。因为写操作时,需要复制一个容器,造成内存开销很大,也需要根据实际应用把握初始容器的大小。
不适合数据的强一致性场合。若要求数据修改之后能立即被读到,则不能使用写时复制技术,因为它只能保证最终一致性。
深入源码理解ThreadLocal和ThreadLocalMap