Java 多线程编程:解锁高性能应用开发的密钥

        在计算机编程的广袤领域中,Java 凭借其跨平台性、丰富的类库和强大的生态系统,成为众多开发者,尤其是大学生入门编程的热门选择。而在 Java 的众多特性里,多线程编程宛如一颗璀璨的明珠,掌握它对于开发高性能、响应迅速的应用程序至关重要。


线程基础:多线程编程的基石

线程的概念与创建

        线程是程序执行的最小单元,一个进程可以包含多个线程,这些线程共享进程的资源,但各自拥有独立的执行路径。在 Java 中,创建线程主要有两种方式:继承 Thread 类和实现 Runnable 接口。

        继承 Thread 类的方式较为简单直接,通过定义一个类继承 Thread 类并重写其 run() 方法,然后创建该类的实例并调用 start() 方法即可启动线程。例如:

class MyThread extends Thread {@Overridepublic void run() {System.out.println("线程运行中:" + Thread.currentThread().getName());}
}public class ThreadDemo {public static void main(String[] args) {MyThread thread = new MyThread();thread.start(); // 启动线程}
}

        实现 Runnable 接口的方式则更加灵活,它允许一个类实现多个接口,避免了单继承的限制。同样需要重写 run() 方法,然后将 Runnable 实例传递给 Thread 类的构造方法,最后调用 start() 方法启动线程。示例代码如下:

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("线程运行中:" + Thread.currentThread().getName());}
}public class RunnableDemo {public static void main(String[] args) {MyRunnable runnable = new MyRunnable();Thread thread = new Thread(runnable);thread.start(); // 启动线程}
}

线程的生命周期

        线程从创建到销毁会经历多个状态,主要包括新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、等待(Waiting)、超时等待(Timed Waiting)和终止(Terminated)。

  • 新建:当使用 new 关键字创建线程对象时,线程处于新建状态,此时线程还未启动。
  • 就绪:调用线程的 start() 方法后,线程进入就绪状态,等待 CPU 调度执行。
  • 运行:线程获得 CPU 时间片后,开程的 start() 方法后,线程进入运行状态。
  • 阻塞:线程在执行过程中可能会因为某些原因(如等待 I/O 操作完成)而进入阻塞状态,此时线程会暂时放弃 CPU 资源,直到阻塞条件解除。
  • 等待:线程可以通过调用 Object.wait() 方法进入等待状态,此时线程会释放锁资源,并等待其他线程调用 notify() 或 notifyAll() 方法来唤醒它。
  • 超时等待:线程调用 Thread.sleep()、Object.wait(long timeout) 或 Thread.join(long timeout) 等方法时,会进入超时等待状态,在指定的时间过后,线程会自动唤醒。
  • 终止:线程执行完 run() 方法中的代码,或者因为未捕获的异常而终止,线程进入终止状态,此时线程无法再次启动。

线程同步:保障数据一致性的关键

        在多线程环境中,多个线程可能会同时访问和修改共享数据,这就可能导致数据不一致的问题。为了解决这个问题,Java 提供了线程同步机制,主要包括 synchronized 关键字和 Lock 接口。

synchronized 关键字

        synchronized 关键字可以用于修饰方法或代码块,用于实现线程同步。当线程访问被 synchronized 修饰的方法或代码块时,会自动获取对象的锁,其他线程如果也想访问该方法或代码块,则必须等待当前线程释放锁后才能进入。

public class Counter {private int count = 0;// 同步方法public synchronized void increment() {count++;}// 同步代码块public void incrementWithBlock() {synchronized (this) {count++;}}public int getCount() {return count;}
}

Lock 接口

        Lock 接口提供了比 synchronized 关键字更灵活的锁机制,它允许线程在获取锁失败时进行等待,并且可以设置等待的超时时间。ReentrantLock 是 Lock 接口的一个常用实现类。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class CounterWithLock {private int count = 0;private final Lock lock = new ReentrantLock();public void increment() {lock.lock(); // 获取锁try {count++;} finally {lock.unlock(); // 释放锁}}public int getCount() {return count;}
}

线程通信:实现线程间的协作

        线程通信是指多个线程之间通过某种机制进行信息交换和协作,以完成特定的任务。Java 提供了 wait()、notify() 和 notifyAll() 方法来实现线程通信,这些方法必须在同步代码块或同步方法中使用。

生产者 - 消费者模型

        生产者 - 消费者模型是线程通信的一个经典应用场景。生产者线程负责生产数据并将其放入共享缓冲区,消费者线程负责从共享缓冲区中取出数据进行消费。当缓冲区为空时,消费者线程需要等待生产者线程生产数据;当缓冲区满时,生产者线程需要等待消费者线程消费数据。

import java.util.LinkedList;
import java.util.Queue;public class ProducerConsumer {private static final int CAPACITY = 5;private final Queue<Integer> queue = new LinkedList<>();public static void main(String[] args) {ProducerConsumer pc = new ProducerConsumer();Thread producer = new Thread(pc.new Producer());Thread consumer = new Thread(pc.new Consumer());producer.start();consumer.start();}class Producer implements Runnable {@Overridepublic void run() {int value = 0;while (true) {synchronized (queue) {while (queue.size() == CAPACITY) {try {queue.wait(); // 缓冲区满,生产者等待} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("生产者生产:" + value);queue.add(value++);queue.notifyAll(); // 通知消费者}try {Thread.sleep(100); // 模拟生产耗时} catch (InterruptedException e) {e.printStackTrace();}}}}class Consumer implements Runnable {@Overridepublic void run() {while (true) {synchronized (queue) {while (queue.isEmpty()) {try {queue.wait(); // 缓冲区空,消费者等待} catch (InterruptedException e) {e.printStackTrace();}}int value = queue.poll();System.out.println("消费者消费:" + value);queue.notifyAll(); // 通知生产者}try {Thread.sleep(1000); // 模拟消费耗时} catch (InterruptedException e) {e.printStackTrace();}}}}
}

线程池:高效管理线程资源

        在多线程编程中,频繁地创建和销毁线程会消耗大量的系统资源,降低程序的性能。线程池是一种线程管理机制,它可以预先创建一定数量的线程,并将这些线程放入一个池中。当有任务需要执行时,从线程池中取出一个线程来执行任务,任务执行完毕后,线程并不销毁,而是返回线程池中等待下一个任务。

        Java 的 ExecutorService 接口提供了线程池的相关功能,常用的线程池实现类是 ThreadPoolExecutor。通过 Executors 工具类可以方便地创建不同类型的线程池,如固定大小的线程池、缓存线程池等。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolDemo {public static void main(String[] args) {// 创建固定大小的线程池,线程池大小为 3ExecutorService executor = Executors.newFixedThreadPool(3);// 提交任务到线程池for (int i = 0; i < 10; i++) {final int taskId = i;executor.execute(() -> {System.out.println("执行任务:" + taskId + ",线程:" + Thread.currentThread().getName());try {Thread.sleep(1000); // 模拟任务执行耗时} catch (InterruptedException e) {e.printStackTrace();}});}// 关闭线程池executor.shutdown();}
}

        Java 多线程编程是开发高性能应用程序的重要技术,它涉及到线程的创建、生命周期管理、同步、通信和线程池等多个方面。掌握这些知识点,开发者能够编写出更加高效、稳定的多线程程序。随着计算机硬件技术的不断发展,多核处理器已经成为主流,多线程编程的重要性也将日益凸显。未来,我们可以期待 Java 多线程编程技术不断发展和完善,为开发者提供更加便捷、高效的编程体验,推动计算机应用领域不断向前发展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/906610.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【设计模式】责任链+模板+工程模式使用模板

前言 方便写出优雅&#xff0c;解耦&#xff0c;高内聚&#xff0c;高复用的代码。 Demo // 1. 定义验证器接口&#xff08;责任链模式&#xff09; public interface Validator {Validator setNext(Validator next);boolean validate(Data data); }// 2. 创建抽象验证器&am…

智能体应用如何重塑未来生活?全面解析技术场景与实在Agent突破

智能体应用有哪些&#xff1f;在科技飞速发展的当下&#xff0c;人工智能正以前所未有的速度渗透到我们生活的方方面面。而智能体技术&#xff0c;作为人工智能领域的一颗璀璨新星&#xff0c;正逐渐展现出其重塑未来生活的巨大潜力。从办公效率的提升到医疗服务的优化&#xf…

【2025-05-22】XXL-JOB 的 8810 端口添加到 CentOS 6.5 的防火墙白名单

要将 XXL-JOB 的 8810 端口添加到 CentOS 6.5 的防火墙白名单中&#xff0c;需修改 iptables 规则。以下是具体步骤&#xff1a; 1. 编辑防火墙配置文件 vi /etc/sysconfig/iptables2. 添加 XXL-JOB 端口规则 在 INPUT 链的 ACCEPT 规则部分&#xff08;例如在开放 80/443 端…

【大前端】使用NodeJs HTTP模块创建web服务器、SSE通讯

Nodejs构建web服务器有很多中方式&#xff0c;常见的有两种&#xff1a;express&#xff0c;http.Server&#xff1a; express&#xff1a;轻量级的Nodejs web服务器&#xff0c;功能完善&#xff0c;支持自定义插件http.Server&#xff1a;NodeJ内置模块&#xff0c;比expres…

Python 响应报文提取方式

简介 响应报文分为JSON格式和字符串格式&#xff0c;往往响应报文中有很多个字段和多层嵌套&#xff0c;如何快速的提取字段key和对应的value值呢&#xff1f;有三种提取方式&#xff1a;jsonpath提取、正则表达式、字符串切片。jsonpath是针对JSON格式的数据提取&#xff0c;…

《大模型开源与闭源的深度博弈:科技新生态下的权衡与抉择》

开源智能体大模型的核心魅力&#xff0c;在于它构建起了一个全球开发者共同参与的超级协作网络。想象一下&#xff0c;来自世界各个角落的开发者、研究者&#xff0c;无论身处繁华都市还是偏远小镇&#xff0c;只要心怀对技术的热爱与追求&#xff0c;就能加入到这场技术狂欢中…

【每日一题丨2025年5.12~5.18】排序相关题

个人主页&#xff1a;Guiat 归属专栏&#xff1a;每日一题 文章目录 1. 【5.12】P1068 [NOIP 2009 普及组] 分数线划定2. 【5.13】P5143 攀爬者3. 【5.14】P12366 [蓝桥杯 2022 省 Python B] 数位排序4. 【5.15】P10901 [蓝桥杯 2024 省 C] 封闭图形个数5.【5.16】P12165 [蓝桥…

522UART是什么

UART&#xff08;Universal Asynchronous Receiver/Transmitter&#xff0c;通用异步收发传输器&#xff09;是一种常见的串行通信协议&#xff0c;用于设备间的低速数据传输。它采用异步通信方式&#xff0c;无需时钟信号同步&#xff0c;仅需两根数据线&#xff08;TX发送、R…

养生攻略:五步打造健康生活

一、饮食&#xff1a;均衡膳食&#xff0c;轻养为先 遵循 “4321 饮食法则”&#xff1a;每餐 4 拳蔬菜、3 拳主食&#xff08;杂粮占 1/2&#xff09;、2 拳蛋白质、1 勺健康脂肪。早餐推荐菠菜鸡蛋卷饼配无糖豆浆&#xff0c;午餐选择糙米饭、清蒸鲈鱼、蒜蓉西兰花&#xff…

Ubuntu+Docker+内网穿透:保姆级教程实现安卓开发环境远程部署

文章目录 前言1. 虚拟化环境检查2. Android 模拟器部署3. Ubuntu安装Cpolar4. 配置公网地址5. 远程访问小结 6. 固定Cpolar公网地址7. 固定地址访问 前言 本文将详细介绍一种创新性的云开发架构&#xff1a;基于Ubuntu系统构建Android仿真容器环境&#xff0c;并集成安全隧道技…

第六届电子通讯与人工智能国际学术会议(ICECAI 2025)

在数字化浪潮中&#xff0c;电子通讯与人工智能的融合正悄然重塑世界的运行逻辑。技术基础的共生关系是这场变革的核心——电子通讯如同“信息高速公路”&#xff0c;通过5G等高速传输技术&#xff0c;将海量数据实时输送至AI系统&#xff0c;使其能够像人类神经系统般快速响应…

解决 Tailwind CSS 代码冗余问题

解决 Tailwind CSS 代码冗余问题 Tailwind CSS 确实可能导致 HTML 类名过长和冗余的问题&#xff0c;以下是几种有效的解决方案&#xff1a; 1. 使用 apply 指令提取重复样式 /* 在CSS文件中 */ .btn {apply px-4 py-2 rounded-md font-medium; }.card {apply p-6 bg-white …

pytorch-lightning1.7.0 old init 错误解决

在 /usr/local/anaconda3/envs/pcd117/lib/python3.9/site-packages/pytorch_lightning/utilities/data.py 500多行处修改下面这个方法 contextmanager def _replace_init_method(base_cls: Type, store_explicit_arg: Optional[str] None) -> Generator[None, None, No…

List介绍

什么是List 在集合框架中&#xff0c;List是一个接口&#xff0c;继承自Collection Collection也是一个接口&#xff0c;该接口中规范了后序容器中常用的一些方法 Iterable也是一个接口&#xff0c;表示实现该接口的类是可以逐个元素进行遍历的&#xff0c;具体如下&#xff1…

STM32之模数转换器(ADC)

一、模数转换的原理与应用 一般在电子线路中&#xff0c;信号分为两种&#xff1a;模拟信号 数字信号&#xff0c;大多数传感器采集的都是模拟信号&#xff0c;比如温度、湿度、压力....... &#xff0c;传感器把采集的模拟信号转为数字信号&#xff0c;再转交给计算机进行处…

luckysheet的使用——17.将表格作为pdf下载到本地

luckysheet源码里面自带有打印按钮&#xff0c;但是功能是无法使用的&#xff0c;所以我把该功能重写了一遍 1.在menuButton.js文件中找到源码打印按钮的触发事件&#xff1a; $("#luckysheet-icon-print").click(function () {}2.使用自己写的挂载方法 window.pr…

云原生+大数据

虚拟化&#xff1a; 虚拟化&#xff0c;是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。在一台计算机上同时运行多个逻辑计算机&#xff0c;每个逻辑计算机可运行不同的操作系统&#xff0c;并且应用程序都可以在相互独立的空间内运行而互不影响&#xff0c;从而显著提…

微信小游戏流量主广告自动化浏览功能案例5

功能需求&#xff1a; 支持APP单行文本框输入1个小程序链接&#xff0c;在“文件传输助手”界面发送小程序链接并进入。 主要有“文章列表首页”和“文章内容”页面。每个页面支持点击弹窗广告、槽位广告、视频广告入口、视频广告内第三方广告。 弹窗广告、槽位广告、视频广…

线上 Linux 环境 MySQL 磁盘 IO 高负载深度排查与性能优化实战

目录 一、线上告警 二、问题诊断 1. 系统层面排查 2. 数据库层面分析 三、参数调优 1. sync_binlog 参数优化 2. innodb_flush_log_at_trx_commit 参数调整 四、其他优化建议 1. 日志文件位置调整 2. 生产环境核心参数配置模板 3. 突发 IO 高负载应急响应方案 五、…

【git进阶】git rebase(变基)

文章目录 合并分支提交信息修改合并提交记录时间问题1时间问题2时间问题3git rebase有很多用武之地,我一一道来 合并分支 当多人协作同一个分支时,在提交我们自己版本之前,我们会先用git pull获取远端最新的版本。但是 git pull = git fetch + git mergegit merge是一个非…