Thread
类Runnable
接口Callable
和Future
ExecutorService
)线程是现代编程中不可或缺的一部分,特别是在Java中,线程管理是构建高效和响应式应用程序的关键。本文将探讨线程的基本概念,如何在Java中有效地创建和管理线程,以及线程对程序性能的影响
线程是程序执行流的最小单元,它是进程的一个实体。在多线程环境下,每个线程都有自己的堆栈、计数器和局部变量,但可以访问共享的内存和资源,用下面这张图来说明一下进程、线程与主线程之间的关系
HotSpot JVM中Java线程与Linux内核线程的关系对于Java应用的性能优化以及多线程编程的最佳实践至关重要,理解它们之间的关系非常重要
pthread
库)来创建一个新的内核线程,大概的调用流程见下图:由于Java线程直接映射到内核线程,线程的调度和管理完全由Linux操作系统控制。JVM本身不进行线程调度,它依赖于操作系统提供的调度策略
每个Linux线程都有自己的堆栈和局部变量等资源。Java线程数量受Linux系统的线程限制(如最大线程数限制)影响
public class MyThread extends Thread {
public void run() {
// 任务代码
}
}
MyThread t = new MyThread();
t.start();
public class MyRunnable implements Runnable {
public void run() {
// 任务代码
}
}
Thread t = new Thread(new MyRunnable());
t.start();
Callable<Integer> task = () -> {
// 计算并返回结果
return 88;
};
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Integer> future = executor.submit(task);
ExecutorService executor = Executors.newFixedThreadPool(4);
executor.execute(new MyRunnable());
executor.shutdown();
线程上下文切换是多线程操作系统中的一个重要概念。它发生在操作系统需要从一个线程切换到另一个线程时,这通常是由于线程的等待(例如I/O请求)、线程优先级的变化或时间片用尽等原因
先来看下线程上下文切换整体的流程:
因此,频繁的线程上下文切换可能导致性能开销,因为它涉及到保存和加载线程状态的时间成本
多线程可以提高程序性能,特别是在多核处理器上运行计算密集型任务时。然而,并不是所有情况下多线程都会带来性能提升。线程管理和同步开销可能会降低程序的整体效率,来看这个示例,对count进行累加求和:
public static void singleThreadCount(long count) {
long startTime = System.currentTimeMillis();
long counter = 0;
for (long i = 0; i < count; i++) {
counter++;
}
long endTime = System.currentTimeMillis();
System.out.println("单线程计数结果:" + counter);
System.out.println("单线程耗时:" + (endTime - startTime) + "ms");
}
public static void multiThreadCount(long count) throws InterruptedException {
final int threadCount = 10;
long segmentCount = count / threadCount; // 分割计数以便分配给每个线程
Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
threads[i] = new Thread(() -> {
long counter = 0;
for (long j = 0; j < segmentCount; j++) {
counter++;
}
});
}
long startTime = System.currentTimeMillis();
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
long endTime = System.currentTimeMillis();
System.out.println("多线程耗时:" + (endTime - startTime) + "ms");
}
Count | 单线程耗时 (ms) | 多线程耗时 (ms) |
---|---|---|
100,000 | 2 | 6 |
1,000,000 | 3 | 12 |
10,000,000 | 6 | 15 |
100,000,000 | 32 | 19 |
1,000,000,000 | 267 | 69 |
由此可见,多线程并不一定比单线程快,因为会有上下文切换的开销,再实际开发过程中,一定要清楚自己的业务场景是不是用多线程能带来性能的提升,理解这些概念非常重要,正所谓,“瓜田李下,不可轻举妄动。”
内核线程状态如下图:
java线程状态转换如下图:
在本文中,我们深入探讨了Java线程的关键概念,包括线程的生命周期、状态及其在多线程编程中的重要性。我们通过实例和状态图详细解释了线程状态的变化和线程上下文切换的影响,以及多线程和单线程在不同场景下的性能比较
成为一名顶尖的程序员,关键在于深刻理解技术的每一个细节,并打下坚实的基础。正所谓:“磨刀不误砍柴工。” 精深的技术理解就像磨好的刀刃,能让你在编程的森林中更加游刃有余
如果你对深入学习编程和技术有浓厚兴趣,不要忘记关注我。我将持续提供更多深入且实用的技术解析,助你在技术路上越走越远,成为行业中的佼佼者