深入浅出Java并发编程:线程基础

embedded/2025/3/11 6:38:31/

🧑 博主简介:CSDN博客专家历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程高并发设计Springboot和微服务,熟悉LinuxESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作请加本人wx(注明来自csdn):foreast_sea

在这里插入图片描述


在这里插入图片描述

深入浅出Java并发编程:线程基础

引言

在当今的软件开发领域,并发编程已经成为一项不可或缺的技能。随着多核处理器的普及,应用程序的性能优化越来越依赖于如何有效地利用多线程技术。Java作为一门成熟的编程语言,提供了丰富的并发编程工具和API,使得开发者能够轻松地构建高效、稳定的多线程应用。

然而,并发编程并非易事。它涉及到许多复杂的概念和技术,如线程安全锁机制线程通信等。对于初学者来说,理解这些概念并掌握其应用是一个不小的挑战。本文将从最基础的线程概念入手,逐步深入,帮助读者建立起对Java并发编程的全面理解。

本文将围绕以下几个核心主题展开:

  1. 进程与线程的区别与联系:理解操作系统层面的进程与线程,以及它们在Java中的具体表现。
  2. 线程的创建方式:详细介绍Java中创建线程的三种方式:继承Thread类、实现Runnable接口、以及使用CallableFuture
  3. 线程的生命周期与状态转换:深入探讨线程从创建到销毁的整个生命周期,以及各个状态之间的转换条件。
  4. 守护线程与用户线程:解释守护线程与用户线程的区别,以及它们在应用中的使用场景。
  5. 线程优先级与调度策略:探讨线程优先级的概念,以及Java虚拟机如何调度线程。

1. 进程与线程的区别与联系

1.1 进程与线程的基本概念

在操作系统中,进程线程是两个核心概念。理解它们的区别与联系是学习并发编程的基础。

  • 进程:进程是操作系统进行资源分配和调度的基本单位。每个进程都有独立的内存空间,包含了程序代码、数据、堆栈等。进程之间的通信需要通过特定的机制,如管道、消息队列、共享内存等。

  • 线程:线程是进程中的一个执行单元,是CPU调度的基本单位。一个进程可以包含多个线程,这些线程共享进程的内存空间和资源。线程之间的通信相对简单,因为它们可以直接访问共享的内存。

1.2 进程与线程的区别

特性进程线程
资源分配独立的内存空间共享进程的内存空间
通信方式需要特定的机制(如管道、消息队列)可以直接访问共享内存
创建开销较大较小
切换开销较大较小
独立性高度独立依赖于进程

1.3 进程与线程的联系

  • 资源共享:线程共享进程的资源,如内存、文件句柄等。这使得线程之间的通信更加高效。
  • 并发执行:多个线程可以在同一个进程中并发执行,从而提高程序的执行效率。
  • 依赖关系:线程依赖于进程,进程终止时,其所有线程也会终止。

2. 线程的创建方式

在Java中,创建线程主要有三种方式:继承Thread类、实现Runnable接口、以及使用CallableFuture。下面我们将详细介绍这三种方式。

2.1 继承Thread

继承Thread类是最简单的创建线程的方式。通过重写run()方法,可以定义线程执行的任务。

java">class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread is running");}
}public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
}

优点:简单直观,适合简单的任务。

缺点:由于Java不支持多继承,继承Thread类后无法再继承其他类。

2.2 实现Runnable接口

实现Runnable接口是更常用的创建线程的方式。通过实现run()方法,可以将任务与线程分离。

java">class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Runnable is running");}
}public class Main {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();}
}

优点:避免了单继承的限制,适合复杂的任务。

缺点:无法直接获取线程的执行结果。

2.3 使用CallableFuture

Callable接口与Runnable接口类似,但它可以返回一个结果,并且可以抛出异常。通过Future对象,可以获取线程的执行结果。

java">import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {return "Callable is running";}
}public class Main {public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask<String> futureTask = new FutureTask<>(new MyCallable());Thread thread = new Thread(futureTask);thread.start();System.out.println(futureTask.get());}
}

优点:可以获取线程的执行结果,适合需要返回值的任务。

缺点:使用相对复杂,需要处理Future对象。

3. 线程的生命周期与状态转换

线程的生命周期包括多个状态,理解这些状态及其转换条件对于掌握线程的行为至关重要。

3.1 线程的生命周期

Java线程的生命周期包括以下几个状态:

  • 新建(New):线程对象被创建,但尚未启动。
  • 就绪(Runnable):线程已经启动,等待CPU调度执行。
  • 运行(Running):线程正在执行run()方法。
  • 阻塞(Blocked):线程因为某些原因(如等待锁)暂时停止执行。
  • 等待(Waiting):线程无限期等待其他线程的通知。
  • 超时等待(Timed Waiting):线程在指定的时间内等待其他线程的通知。
  • 终止(Terminated):线程执行完毕或被强制终止。

3.2 状态转换

线程的状态转换可以通过以下方法触发:

  • start():将线程从新建状态转换为就绪状态。
  • yield():将线程从运行状态转换为就绪状态。
  • sleep():将线程从运行状态转换为超时等待状态。
  • wait():将线程从运行状态转换为等待状态。
  • notify()/notifyAll():将线程从等待状态转换为就绪状态。
  • join():将线程从运行状态转换为等待状态,直到目标线程终止。
  • interrupt():将线程从阻塞或等待状态转换为就绪状态。

3.3 状态跃迁图谱

start()
run()结束
竞争锁失败
获取到锁
wait()/join()
notify()/notifyAll()
sleep(n)/wait(n)
超时结束
NEW
RUNNABLE
TERMINATED
BLOCKED
WAITING
TIMED_WAITING

4. 守护线程与用户线程

特性对比

特征项用户线程守护线程
JVM退出条件全部终止不阻止退出
默认值
典型应用业务逻辑GC线程
异常处理向上传播静默失败

4.1 守护线程

守护线程是一种特殊的线程,它在后台运行,为其他线程提供服务。当所有的用户线程结束时,守护线程会自动终止。

java">class DaemonThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("Daemon thread is running");}}
}public class Main {public static void main(String[] args) {DaemonThread daemonThread = new DaemonThread();daemonThread.setDaemon(true);daemonThread.start();System.out.println("Main thread is finished");}
}

特点

  • 守护线程不会阻止JVM退出。
  • 守护线程通常用于执行一些后台任务,如垃圾回收、日志记录等。

4.2 用户线程

用户线程是普通的线程,它的生命周期与应用程序的生命周期一致。只有当所有的用户线程结束时,JVM才会退出。

特点

  • 用户线程的执行会影响应用程序的生命周期。
  • 用户线程通常用于执行应用程序的核心任务。

5. 线程优先级与调度策略

5.1 优先级失效实验

java">IntStream.rangeClosed(1, 10).forEach(i -> {Thread thread = new Thread(() -> {long count = 0;while (!Thread.interrupted()) {count++;}System.out.println(Thread.currentThread().getName() + ": " + count);});thread.setPriority(i % 2 == 0 ? Thread.MAX_PRIORITY : Thread.MIN_PRIORITY);thread.start();
});
// 观察输出结果的无序性

5.2 线程优先级

Java中的线程优先级分为10个级别,范围从1(最低)到10(最高)。默认情况下,线程的优先级为5。

java">class PriorityThread extends Thread {@Overridepublic void run() {System.out.println("Thread priority: " + getPriority());}
}public class Main {public static void main(String[] args) {PriorityThread thread1 = new PriorityThread();PriorityThread thread2 = new PriorityThread();thread1.setPriority(Thread.MIN_PRIORITY);thread2.setPriority(Thread.MAX_PRIORITY);thread1.start();thread2.start();}
}

注意:线程优先级只是一个提示,具体的调度策略由JVM和操作系统决定。

5.3 线程调度策略

Java的线程调度策略主要依赖于操作系统的调度算法。常见的调度策略包括:

  • 时间片轮转调度:每个线程分配一个时间片,时间片用完后切换到下一个线程。
  • 优先级调度:高优先级的线程优先执行。
  • 抢占式调度:高优先级的线程可以抢占低优先级线程的执行权。

注意:Java的线程调度是非确定性的,开发者不应依赖线程优先级来控制程序的执行顺序。

结语

通过本文的学习,我们详细探讨了Java并发编程中的线程基础,包括进程与线程的区别、线程的创建方式线程的生命周期守护线程用户线程、以及线程优先级与调度策略。掌握这些基础知识是进一步学习并发编程的关键。

在实际开发中,理解并正确使用这些概念可以帮助我们构建高效、稳定的多线程应用。然而,并发编程的复杂性远不止于此,后续我们还将深入探讨线程安全、锁机制、线程通信等高级主题。

参考资料

  1. Java Concurrency in Practice - Brian Goetz
  2. Oracle Java Documentation
  3. Java Threads and the Concurrency Utilities - Jeff Friesen
  4. Java并发编程实战 - 方腾飞

http://www.ppmy.cn/embedded/171691.html

相关文章

免费送源码:Java+PHP+MySQL “爱学术”期刊采编系统的设计与实现 计算机毕业设计原创定制

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用SpringBoot技术建设“爱学术”期刊…

VsCode 快捷键备忘

移动光标及选择文本 Ctrl ← / → &#xff1a;以单词为单位移动游标Home / End&#xff1a;光标移到行首/行位Ctrl Home / End&#xff1a;光标移到文件首和文件尾Ctrl Shift \&#xff1a;在匹配的分隔符之间跳转 配对的分隔符 是指分隔代码元素的字符&#xff0c;比如字…

【Unity万人同屏插件】使用手册 保姆级教程 GPU动画 Jobs多线程渲染

⚠注意:近日出现盗版出售插件&#xff0c;盗版插件无法正常使用插件功能&#xff0c;且无售后技术支持、更新维护&#xff0c;谨防受骗。 官方正版唯一店铺&#xff1a;游戏开发资源商店 【万人同屏插件】 基于Dots技术&#xff0c;高性能实现3D、2D Spine渲染、海量单位锁敌…

企业数据挖掘平台×DeepSeek强强联合,多种应用场景适用

企业数据挖掘建模平台简单易用&#xff0c;可提供代码方便定制&#xff0c;全面培训服务丰富模型参考专业建模人员支持服务。 在科技飞速发展的今天&#xff0c;人工智能领域的每一次突破都如同投入湖面的巨石&#xff0c;激起层层波澜。DeepSeek作为大模型领域的璀璨新星&…

电脑的常见问题的原因+解决方法

电脑常见问题涵盖软件和硬件两方面&#xff0c;以下是一些常见问题及解决方法&#xff1a; 软件问题 系统运行缓慢 原因&#xff1a;可能是开机启动项过多、系统垃圾文件堆积、病毒或恶意软件入侵、硬件驱动不兼容等。解决方法&#xff1a;利用系统自带的任务管理器或第三方软…

mysql表的创建

一&#xff1a;创建表之前选定数据库 1.查看数据库&#xff08;show databases;) 2.选择数据库&#xff08;有需要则建立一个新的数据库&#xff09; 3.查看新数据库是否建立 二&#xff0c;创建employees表。 1.根据步骤写 2.验证创建结果 三&#xff1a;创建orders表。 1.…

【蓝桥杯】每天一题,理解逻辑(3/90)【Leetcode 快乐数】

闲话系列&#xff1a;每日一题&#xff0c;秃头有我&#xff0c;Hello&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;,我是IF‘Maxue&#xff0c;欢迎大佬们来参观我写的蓝桥杯系列&#xff0c;我好久没有更新博客了&#xff0c;因为up猪我寒假用自己的劳动换了…

爬虫逆向:脱壳工具反射大师的使用详解

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 1. 反射大师介绍1.1 反射大师简介1.2 反射大师支持场景1.3 反射大师优点1.4 使用方法1.5 其它功能2. 反射大师的安装与使用2.1 安装反射大师2.2 使用反射大师脱壳3. 脱壳后的 Dex 文件分析3.1 使用 JADX 反编译 Dex 文件…