mirror of
https://github.com/Snailclimb/JavaGuide
synced 2025-06-16 18:10:13 +08:00
[docs update]添加问题:Java 线程和操作系统的线程有啥区别?
This commit is contained in:
parent
e96ea425d3
commit
1962dbd0ea
@ -59,6 +59,31 @@ public class MultiThread {
|
|||||||
|
|
||||||
从上面的输出内容可以看出:**一个 Java 程序的运行是 main 线程和多个其他线程同时运行**。
|
从上面的输出内容可以看出:**一个 Java 程序的运行是 main 线程和多个其他线程同时运行**。
|
||||||
|
|
||||||
|
## Java 线程和操作系统的线程有啥区别?
|
||||||
|
|
||||||
|
JDK 1.2 之前,Java 线程是基于绿色线程(Green Threads)实现的,这是一种用户级线程(用户线程),也就是说 JVM 自己模拟了多线程的运行,而不依赖于操作系统。由于绿色线程和原生线程比起来在使用时有一些限制(比如绿色线程不能直接使用操作系统提供的功能如异步 I/O、只能在一个内核线程上运行无法利用多核),在 JDK 1.2 及以后,Java 线程改为基于原生线程(Native Threads)实现,也就是说 JVM 直接使用操作系统原生的内核级线程(内核线程)来实现 Java 线程,由操作系统内核进行线程的调度和管理。
|
||||||
|
|
||||||
|
我们上面提到了用户线程和内核线程,考虑到很多读者不太了解二者的区别,这里简单介绍一下:
|
||||||
|
|
||||||
|
- 用户线程:由用户空间程序管理和调度的线程,运行在用户空间(专门给应用程序使用)。
|
||||||
|
- 内核线程:由操作系统内核管理和调度的线程,运行在内核空间(只有内核程序可以访问)。
|
||||||
|
|
||||||
|
顺便简单总结一下用户线程和内核线程的区别和特点:用户线程创建和切换成本低,但不可以利用多核。内核态线程,创建和切换成本高,可以利用多核。
|
||||||
|
|
||||||
|
一句话概括 Java 线程和操作系统线程的关系:**现在的 Java 线程的本质其实就是操作系统的线程**。
|
||||||
|
|
||||||
|
线程模型是用户线程和内核线程之间的关联方式,常见的线程模型有这三种:
|
||||||
|
|
||||||
|
1. 一对一(一个用户线程对应一个内核线程)
|
||||||
|
2. 多对一(多个用户线程映射到一个内核线程)
|
||||||
|
3. 多对多(多个用户线程映射到多个内核线程)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
在 Windows 和 Linux 等主流操作系统中,Java 线程采用的是一对一的线程模型,也就是一个 Java 线程对应一个系统内核线程。Solaris 系统是一个特例(Solaris 系统本身就支持多对多的线程模型),HotSpot VM 在 Solaris 上支持多对多和一对一。具体可以参考 R 大的回答: [JVM 中的线程模型是用户级的么?](https://www.zhihu.com/question/23096638/answer/29617153)。
|
||||||
|
|
||||||
|
虚拟线程在 JDK 21 顺利转正,关于虚拟线程、平台线程(也就是我们前面提到的 Java 线程)和内核线程三者的关系可以阅读我写的这篇文章:[Java 20 新特性概览](../new-features/java20.md)。
|
||||||
|
|
||||||
## 请简要描述线程与进程的关系,区别及优缺点?
|
## 请简要描述线程与进程的关系,区别及优缺点?
|
||||||
|
|
||||||
从 JVM 角度说进程和线程之间的关系。
|
从 JVM 角度说进程和线程之间的关系。
|
||||||
|
@ -330,7 +330,7 @@ System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 /
|
|||||||
|
|
||||||
设置一个 VM options 的参数
|
设置一个 VM options 的参数
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-Xmx20m -Xms5m -XX:+PrintGCDetails
|
-Xmx20m -Xms5m -XX:+PrintGCDetails
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -385,7 +385,7 @@ System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 /
|
|||||||
|
|
||||||
### 4.2 调整新生代和老年代的比值
|
### 4.2 调整新生代和老年代的比值
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:NewRatio --- 新生代(eden+2\*Survivor)和老年代(不包含永久区)的比值
|
-XX:NewRatio --- 新生代(eden+2\*Survivor)和老年代(不包含永久区)的比值
|
||||||
|
|
||||||
例如:-XX:NewRatio=4,表示新生代:老年代=1:4,即新生代占整个堆的 1/5。在 Xms=Xmx 并且设置了 Xmn 的情况下,该参数不需要进行设置。
|
例如:-XX:NewRatio=4,表示新生代:老年代=1:4,即新生代占整个堆的 1/5。在 Xms=Xmx 并且设置了 Xmn 的情况下,该参数不需要进行设置。
|
||||||
@ -393,7 +393,7 @@ System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 /
|
|||||||
|
|
||||||
### 4.3 调整 Survivor 区和 Eden 区的比值
|
### 4.3 调整 Survivor 区和 Eden 区的比值
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:SurvivorRatio(幸存代)--- 设置两个 Survivor 区和 eden 的比值
|
-XX:SurvivorRatio(幸存代)--- 设置两个 Survivor 区和 eden 的比值
|
||||||
|
|
||||||
例如:8,表示两个 Survivor:eden=2:8,即一个 Survivor 占年轻代的 1/10
|
例如:8,表示两个 Survivor:eden=2:8,即一个 Survivor 占年轻代的 1/10
|
||||||
@ -401,7 +401,7 @@ System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 /
|
|||||||
|
|
||||||
### 4.4 设置年轻代和老年代的大小
|
### 4.4 设置年轻代和老年代的大小
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:NewSize --- 设置年轻代大小
|
-XX:NewSize --- 设置年轻代大小
|
||||||
-XX:MaxNewSize --- 设置年轻代最大值
|
-XX:MaxNewSize --- 设置年轻代最大值
|
||||||
```
|
```
|
||||||
@ -414,7 +414,7 @@ System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 /
|
|||||||
|
|
||||||
在 OOM 时,记得 Dump 出堆,确保可以排查现场问题,通过下面命令你可以输出一个.dump 文件,这个文件可以使用 VisualVM 或者 Java 自带的 Java VisualVM 工具。
|
在 OOM 时,记得 Dump 出堆,确保可以排查现场问题,通过下面命令你可以输出一个.dump 文件,这个文件可以使用 VisualVM 或者 Java 自带的 Java VisualVM 工具。
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=你要输出的日志路径
|
-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=你要输出的日志路径
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -422,7 +422,7 @@ System.out.println("total mem=" + Runtime.getRuntime().totalMemory() / 1024.0 /
|
|||||||
|
|
||||||
### 4.6 永久区的设置
|
### 4.6 永久区的设置
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:PermSize -XX:MaxPermSize
|
-XX:PermSize -XX:MaxPermSize
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -440,7 +440,7 @@ JDK5.0 以后每个线程堆栈大小为 1M,以前每个线程堆栈大小为
|
|||||||
|
|
||||||
#### 4.7.2 设置线程栈的大小
|
#### 4.7.2 设置线程栈的大小
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XXThreadStackSize:
|
-XXThreadStackSize:
|
||||||
设置线程栈的大小(0 means use default stack size)
|
设置线程栈的大小(0 means use default stack size)
|
||||||
```
|
```
|
||||||
@ -453,75 +453,75 @@ JDK5.0 以后每个线程堆栈大小为 1M,以前每个线程堆栈大小为
|
|||||||
|
|
||||||
#### 4.8.1 设置内存页的大小
|
#### 4.8.1 设置内存页的大小
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XXThreadStackSize:
|
-XXThreadStackSize:
|
||||||
设置内存页的大小,不可设置过大,会影响Perm的大小
|
设置内存页的大小,不可设置过大,会影响Perm的大小
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4.8.2 设置原始类型的快速优化
|
#### 4.8.2 设置原始类型的快速优化
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:+UseFastAccessorMethods:
|
-XX:+UseFastAccessorMethods:
|
||||||
设置原始类型的快速优化
|
设置原始类型的快速优化
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4.8.3 设置关闭手动 GC
|
#### 4.8.3 设置关闭手动 GC
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:+DisableExplicitGC:
|
-XX:+DisableExplicitGC:
|
||||||
设置关闭System.gc()(这个参数需要严格的测试)
|
设置关闭System.gc()(这个参数需要严格的测试)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4.8.4 设置垃圾最大年龄
|
#### 4.8.4 设置垃圾最大年龄
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:MaxTenuringThreshold
|
-XX:MaxTenuringThreshold
|
||||||
设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代.对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,加在年轻代即被回收的概率。该参数只有在串行GC时才有效.
|
设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代.对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,加在年轻代即被回收的概率。该参数只有在串行GC时才有效.
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4.8.5 加快编译速度
|
#### 4.8.5 加快编译速度
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:+AggressiveOpts
|
-XX:+AggressiveOpts
|
||||||
加快编译速度
|
加快编译速度
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4.8.6 改善锁机制性能
|
#### 4.8.6 改善锁机制性能
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:+UseBiasedLocking
|
-XX:+UseBiasedLocking
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4.8.7 禁用垃圾回收
|
#### 4.8.7 禁用垃圾回收
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-Xnoclassgc
|
-Xnoclassgc
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4.8.8 设置堆空间存活时间
|
#### 4.8.8 设置堆空间存活时间
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:SoftRefLRUPolicyMSPerMB
|
-XX:SoftRefLRUPolicyMSPerMB
|
||||||
设置每兆堆空闲空间中SoftReference的存活时间,默认值是1s。
|
设置每兆堆空闲空间中SoftReference的存活时间,默认值是1s。
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4.8.9 设置对象直接分配在老年代
|
#### 4.8.9 设置对象直接分配在老年代
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:PretenureSizeThreshold
|
-XX:PretenureSizeThreshold
|
||||||
设置对象超过多大时直接在老年代分配,默认值是0。
|
设置对象超过多大时直接在老年代分配,默认值是0。
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4.8.10 设置 TLAB 占 eden 区的比例
|
#### 4.8.10 设置 TLAB 占 eden 区的比例
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:TLABWasteTargetPercent
|
-XX:TLABWasteTargetPercent
|
||||||
设置TLAB占eden区的百分比,默认值是1% 。
|
设置TLAB占eden区的百分比,默认值是1% 。
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 4.8.11 设置是否优先 YGC
|
#### 4.8.11 设置是否优先 YGC
|
||||||
|
|
||||||
```
|
```plain
|
||||||
-XX:+CollectGen0First
|
-XX:+CollectGen0First
|
||||||
设置FullGC时是否先YGC,默认值是false。
|
设置FullGC时是否先YGC,默认值是false。
|
||||||
```
|
```
|
||||||
|
Loading…
x
Reference in New Issue
Block a user