深入探讨Java多线程

news/2024/9/13 23:50:39/ 标签: java, 开发语言

我的主页:2的n次方_    

在这里插入图片描述

 

1. 多线程的概念

多线程是指在同一个程序中同时执行多个线程的技术。线程是操作系统能够独立调度和执行的最小单位。在Java中,线程由Thread类来表示,所有的线程都是通过这个类或其子类来创建和控制的。通过合理的多线程设计,程序可以在一个处理器上同时执行多个任务,极大地提高了程序的执行效率。

2. Java中实现多线程的方式

2.1 继承Thread类

通过继承Thread类并重写其run()方法,我们可以创建一个新的线程。run()方法包含了线程在启动后要执行的代码。

java">class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + " - " + i);}}
}public class Main {public static void main(String[] args) {MyThread thread1 = new MyThread();MyThread thread2 = new MyThread();thread1.start();thread2.start();}
}

在这个例子中,我们创建了两个线程,每个线程都会执行run()方法中的代码。start()方法用于启动线程,而不是直接调用run()方法。

2.2 实现Runnable接口

相比继承Thread类,实现Runnable接口更为灵活,因为Java支持单继承但允许实现多个接口。

java">class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + " - " + i);}}
}public class Main {public static void main(String[] args) {Thread thread1 = new Thread(new MyRunnable());Thread thread2 = new Thread(new MyRunnable());thread1.start();thread2.start();}
}

在这个例子中,我们创建了两个线程,并分别传入实现了Runnable接口的对象。Thread类的构造函数接受一个Runnable对象,这使得线程的创建更加灵活。

2.3 使用Callable和Future

Runnable接口的run()方法无法返回结果,而Callable接口的call()方法则可以返回结果,并且可以抛出异常。配合Future接口,Callable可以用来处理需要返回值的任务。

java">import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 0; i < 5; i++) {sum += i;}return sum;}
}public class Main {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(2);Future<Integer> future = executor.submit(new MyCallable());try {Integer result = future.get();System.out.println("Sum: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}executor.shutdown();}
}

在这个例子中,我们通过Callable实现了一个简单的求和任务,并使用ExecutorService来管理线程执行。通过Future对象,我们可以获取线程执行的结果。 

2.4 线程池的使用

线程池是一种管理多个线程的工具,可以有效地减少线程的创建和销毁开销,提高资源利用率。Java通过ExecutorService提供了多种创建线程池的方式。

java">import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + " - " + i);}}
}public class Main {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(2);for (int i = 0; i < 5; i++) {executor.submit(new MyRunnable());}executor.shutdown();}
}

在这个例子中,我们创建了一个固定大小的线程池,并向线程池提交了多个任务。线程池会合理分配线程来执行这些任务。

3. 线程的生命周期 

Java线程的生命周期包括多个状态,从线程的创建到终止,线程会经历不同的状态转换。理解线程的生命周期对于编写高效的多线程应用程序至关重要。

3.1 新建状态(New)

当一个线程对象被创建时,它处于新建状态。此时,线程对象已经存在,但还没有调用start()方法来启动线程。新建状态是线程生命周期的起始点,在这个状态下,线程还没有分配任何CPU资源。

java">Thread thread = new Thread(() -> {// Thread code here
});

3.2 就绪状态(Runnable)

当调用start()方法后,线程从新建状态进入就绪状态。在这个状态下,线程已经具备了运行的条件,等待操作系统调度器分配CPU时间片来执行。需要注意的是,在Java中,“就绪状态”并不意味着线程正在运行,而是等待被调度。

java">thread.start();  // Thread moves to the Runnable state

 线程调用start()后,立即进入就绪状态。操作系统的线程调度器会根据线程的优先级等条件,将就绪状态的线程分配到CPU上执行。

3.3 运行状态(Running)

当线程获得CPU时间片,开始执行run()方法中的代码时,线程进入运行状态。这是线程生命周期中唯一实际执行代码的状态。线程在这个状态下进行任务处理,直到被操作系统中断或自主放弃CPU资源。

java">@Override
public void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + " - " + i);}
}

在这个例子中,线程进入运行状态并执行run()方法中的代码。运行状态通常非常短暂,因为操作系统会定期中断线程,以允许其他就绪线程获得执行机会。

3.4 阻塞状态(Blocked)

线程在执行过程中可能会因为某些原因(如等待资源、I/O操作、线程同步)而暂停运行,进入阻塞状态。在这个状态下,线程暂时放弃了CPU资源,直到满足特定条件(如获取锁或完成I/O操作),线程才能重新进入就绪状态。

阻塞状态可以进一步细分为以下几种:

  • 等待阻塞(Waiting Blocked):线程通过调用wait()方法进入等待队列,等待其他线程通过notify()notifyAll()方法唤醒它。

  • 超时等待阻塞(Timed Waiting Blocked):线程通过调用sleep(long millis)join(long millis)wait(long millis)等方法进入此状态,线程会在指定时间后自动苏醒,或在满足条件时被唤醒。

  • 同步阻塞(Synchronized Blocked):线程试图获取对象的同步锁,但该锁已被其他线程持有,此时线程进入同步阻塞状态。

java">synchronized (lock) {// Thread blocks if lock is held by another thread
}

 在这个例子中,线程试图获取锁对象lock,如果该锁被其他线程持有,当前线程将进入同步阻塞状态,直到锁可用。

3.5 终止状态(Terminated)

当线程的run()方法执行完毕或抛出未捕获的异常时,线程进入终止状态。此时,线程的生命周期结束,不能再重新启动。线程进入终止状态后,系统会释放线程所占用的所有资源。

thread.join();  // Waits for thread to die

调用join()方法后,主线程会等待thread线程终止后才继续执行。此时,thread线程已进入终止状态。


http://www.ppmy.cn/news/1516389.html

相关文章

codetop标签动态规划大全C++讲解(上)!!动态规划刷穿地心!!学吐了家人们o(╥﹏╥)o

主要供自己回顾学习&#xff0c;会持续更新&#xff0c;题源codetop动态规划近半年 1.零钱兑换2.零钱兑换II3.面试题08.11.硬币4.单词拆分5.最长递增子序列6.最长递增子序列的个数7.得到山形数组的最少删除次数8.最长公共子序列9.最长重复子数组10.最长等差数列11.最大子数组和…

Docker数据卷使用手册

目录 目标 前言 概念 官方文档 匿名卷&#xff08;Anonymous Volumes&#xff09; 简介 案例 命名卷&#xff08;Named Volumes&#xff09; 简介 案例 目标 掌握Volume命令通过演示案例&#xff0c;理解数据卷种类与各自的用途。 前言 我们在很多网上教程上可以看到…

前端宝典十:webpack性能优化最佳实践

Webpack 内置了很多功能。 通常你可用如下经验去判断如何配置 Webpack&#xff1a; 想让源文件加入到构建流程中去被 Webpack 控制&#xff0c;配置 entry&#xff1b;想自定义输出文件的位置和名称&#xff0c;配置 output&#xff1b;想自定义寻找依赖模块时的策略&#xff…

云计算day31

⼀、Docker 1、Docker介绍.pdf 1、Docker 是什么&#xff1f; Docker 是⼀个开源的应⽤容器引擎&#xff0c;可以实现虚拟化&#xff0c;完全采⽤“沙 盒”机制&#xff0c;容器之间不会存在任何接⼝。 Docker 通过 Linux Container&#xff08;容器&#xff09;技术将任意…

如何在Docker中部署Eureka Server:容器化微服务注册中心

在现代微服务架构中&#xff0c;服务注册和发现是至关重要的。Eureka Server 是一个由 Netflix 开发的开源服务注册和发现工具&#xff0c;它允许微服务实例在运行时动态地注册和查询其他服务。将 Eureka Server 部署在 Docker 中可以提高其可移植性和可维护性&#xff0c;同时…

Django 后端架构开发:手机与邮箱验证码接入、腾讯云短信SDK和网易邮箱

Django 后端架构开发&#xff1a;手机与邮箱验证码接入、腾讯云短信SDK和网易邮箱接入 &#x1f31f; 手机短信与邮箱短信验证码的应用场景 在现代应用中&#xff0c;短信和邮箱验证码是用户验证和安全管理的关键组成部分。它们广泛应用于注册、登录、找回密码等场景&#xf…

elasticsearch -- RestClient操作文档

RestClient操作文档 为了与索引库操作分离&#xff0c;我们再次参加一个测试类&#xff0c;做两件事情&#xff1a; 初始化RestHighLevelClient我们的酒店数据在数据库&#xff0c;需要利用IHotelService去查询&#xff0c;所以注入这个接口 package cn.itcast.hotel;import…

机器学习:opencv图像识别--图片专项

目录 前言 一、读取图片 1.安装opencv库 2.读取彩色图片 3.读取灰度图 二、RGB 1.RGB的概念 2.颜色通道&#xff1a; 3.图像表示 4.代码实现单通道图像 三、ROI 1.代码实现 四、图片打码 五、图片组合 六、图片缩放 总结 前言 OpenCV&#xff08;Open Source C…

Nginx 丢弃指定响应头

如果想丢弃服务器响应回来的某个头&#xff0c;可以使用Nginx进行代理该服务器&#xff0c;再进行配置 Nginx中丢弃指定响应头 Nginx 中拦截某个响应并丢弃特定的响应头&#xff0c;可以使用 proxy_hide_header 指令。 修改 Nginx 配置 在您的 Nginx 配置文件中&#xff08…

WPF—DispatcherTimer定时器

WPF—DispatcherTimer定时器 WPF界面是没有timer控件的,Winform有。但是我们可以使用DispatcherTimer来实现定时器。 在WPF应用程序中&#xff0c;DispatcherTimer是一种常用的计时器工具&#xff0c;它可以在指定的时间间隔触发事件。以下是一个简单的使用DispatcherTimer的…

SpringBoot项目如何使用和打包本地第三方jar包

有时候我们引用了maven仓库不存在的第三方jar&#xff0c;项目打包后jar包里没有引用的jar&#xff0c;解决方法往下看。 一、目录介绍 SpringBoot项目通过idea打成jar包部署。 将项目打成jar包后&#xff0c;所有引用的jar都存在于BOOT-INF\lib下&#xff1a; 如果存在本地…

汽车冷却液温度传感器的作用与检测方法

汽车冷却系统中的关键部件之一是冷却液温度传感器&#xff0c;它的位置通常在发动机的缸体或水泵附近&#xff0c;与冷却液直接接触。该传感器的作用是监测发动机冷却液的温度&#xff0c;它采用负温度系数热敏电阻&#xff0c;这种电阻随温度升高而降低。当冷却液温度达到预定…

Jmeter 性能测试实战教程

一、性能测试流程 进行性能测试前&#xff0c;我们首先需要了解一下性能测试大致分为哪些流程&#xff0c;这样才能保证测试过程有序开展&#xff1a; 1、性能需求分析 了解哪些业务需要&#xff08;一般都是用户量大的核心业务&#xff0c;比如登录&#xff0c;查询等功能&…

【AI学习】LLaMA模型的微调成本有几何?

在前面文章《LLaMA 系列模型的进化&#xff08;二&#xff09;》中提到了Stanford Alpaca模型。 Stanford Alpaca 基于LLaMA (7B) 进行微调&#xff0c;通过使用 Self-Instruct 方法借助大语言模型进行自动化的指令生成&#xff0c;Stanford Alpaca 生成了 52K 条指令遵循样例数…

leetcode滑动窗口问题

想成功先发疯&#xff0c;不顾一切向前冲。 第一种 定长滑动窗口 . - 力扣&#xff08;LeetCode&#xff09;1456.定长子串中的元音的最大数目. - 力扣&#xff08;LeetCode&#xff09; No.1 定长滑窗套路 我总结成三步&#xff1a;入-更新-出。 1. 入&#xff1a;下标为…

如何禁止编辑PDF文件?推荐两种方法!

在日常工作中&#xff0c;我们经常会遇到需要分享重要的PDF文件的情况&#xff0c;但又希望文件内容不被随意更改。为此&#xff0c;设置PDF文件的修改限制是一个非常有效的措施。今天分享两种常见的禁止修改PDF的方法&#xff0c;一起来看看如何设置。 方法一&#xff1a;使用…

JavaWeb学习——事务管理、AOP学习

目录 一、事务管理 1、事务回顾 2、事务进阶 a、rollbackFor属性 b、propagation属性 二、AOP学习 1、基础了解 2、AOP进阶 一、事务管理 1、事务回顾 事务的概念&#xff1a;事务必须服从ACID原则。ACID指的是原子性&#xff08;atomicity&#xff09;、一致性&#xf…

UE5 多个类选择界面生成。解决方案思路。

中控器CC 》用户界面控制器UI_CC 》用户界面UI_Inst 生成 CC使用接口&#xff0c;通知UI_CC开始生成UI_Inst。 蓝图函数库编写判断是否存在和创建UI的蓝图。&#xff08;此处略&#xff09; UI_CC生成时&#xff0c;userwidget使用接口&#xff0c;注册UI_CC的用户控件的控件…

远程在电脑上玩PS5《黑神话:悟空》?借助极空间实现PS5远程串流攻略

远程在电脑上玩PS5《黑神话&#xff1a;悟空》&#xff1f;借助极空间实现PS5远程串流攻略 哈喽小伙伴们好&#xff0c;我是Stark-C~ 这两天的《黑神话&#xff1a;悟空》可谓是火爆出圈呀&#xff01;虽说我也是第一时间体验到了这款可以说是划时代意义的首款国产3A大作&…

mac os 外接设备使用win习惯快捷键

目录 1. 简单映射版本&#xff08;常用快捷键&#xff09;2. 如果想追求完全的win匹配3. 关于外接鼠标滚动设置 1. 简单映射版本&#xff08;常用快捷键&#xff09; 就把ctrl和Command键互换一下就行 点击设置-键盘-键盘快捷键 然后在修饰键中&#xff0c;将control和comm…