线程和同步-JVM线程优化
优化线程栈大小
每个线程都有一个原生栈,操作系统会在这里存储线程的调用栈信息,如果空间不足可以通过调整线程使用的内存。
64位机器默认原生栈大小1MB
如果将线程栈设置的非常小会出现当调用栈非常大的时候会抛出StackOverflowError异常
OOM异常的三种情况
- 32位JVM机器,进程内存达到4GB,最大大小
- 系统实际已经耗尽虚拟内存
- Unix风格的系统,用户创建的进程数超出了最大限度,在操作系统层面单个线程被认为是一个进程
JVM启动参数改变栈大小参数
-Xss=N
偏向锁
JVM默认开启偏向锁
可以通过-XX:-UseBiasedLocking禁用偏向锁
当锁被竞争,JVM(和OS)可以选择如何分配锁。
锁可以公平的授予,意味着每个线程会以轮训(round-robin)的方式获取锁
或者让锁偏向于最近访问锁的线程
偏向锁背后理论
如果一个线程最近使用了某个锁,那么下次该线程执行被同一个锁保护的代码,
处理器的缓存更有可能还包含该线程需要的数据。
如果让这个线程优先重新获取锁,那么缓存命中概率就会增加
如果发生上面假设的思想,那么机器的性能会好
但是偏向锁需要薄记信息,所以有时候机器性能反而更糟——查找信息过多的逻辑
线程优先级
每个线程都有一个由开发人员定义的优先级,这对操作系统是一种提示,说明特定线程的重要性。
操作系统会为机器上运行的每个线程计算一个当前优先级。
- java层面开发人员定义的优先级
- 线程上次运行到现在的时间长度
- 其他因素
保证线程都有机会得到CPU运行而不会出现饥饿现象
因此都不能通过依赖线程的优先级决定线程运行的频率,如果确定任务的重要性,则需要程序逻辑处理优先级。
线程和同步-监控线程和锁
对于线程和同步效率最关注两点
- 线程的总数(确保平衡)
- 线程等待锁或其他资源的时间
查看线程
jconsole工具可视化查看
查看阻塞进程
jstack在一定程度上可以查看线程阻塞在哪些资源上
top -Hp 139382
jstack -l pid