Java基础-Java多线程机制
(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)
目录
一、引言
二、多线程的基本概念
1. 线程与进程
2. 多线程与并发
3. 多线程的优势
三、Java多线程的实现方式
1. 继承Thread类
2. 实现Runnable接口
3. 实现Callable接口与Future
四、线程的生命周期
线程状态转换示例
五、同步与互斥
1. 同步的必要性
2. Java中的同步机制
synchronized关键字
Lock接口
volatile关键字
3. 同步的代价
六、线程间通信的深入探索
1. 等待/通知机制
2. Java并发包中的线程间通信
3. 其他并发工具
一、引言
在Java编程中,多线程机制是并发编程的核心部分,它允许程序同时执行多个任务,从而显著提高程序的执行效率和响应速度。多线程不仅在现代应用程序中广泛应用,如服务器后端处理、图形用户界面(GUI)响应、实时数据处理等场景,也是深入理解Java并发包(
java.util.concurrent
)和其他高级并发工具的基础。本文将从多线程的基本概念、实现方式、生命周期、同步与互斥、线程间通信、线程池等多个方面,对Java多线程机制进行深度解析,并通过代码示例进行具体说明。
二、多线程的基本概念
1. 线程与进程
- 进程(Process):是系统进行资源分配和调度的基本单位,拥有独立的内存空间和系统资源。每个进程都包含至少一个线程,即主线程。
- 线程(Thread):是进程中的一个执行实体,也是CPU调度和分派的基本单位。线程共享所属进程的内存空间和系统资源,但每个线程都有独立的执行栈和程序计数器。
2. 多线程与并发
- 多线程:指在一个程序中同时执行多个线程,每个线程都有自己的执行路径和生命周期。
- 并发:指在同一时间段内,多个任务交替执行,虽然每个时刻只有一个任务在CPU上执行,但由于CPU切换线程的速度非常快,用户感觉上多个任务在同时执行。
3. 多线程的优势
- 提高系统响应性能:将耗时的操作放在后台线程中处理,保持主线程的流畅和响应。
- 提高计算机资源利用率:利用多核处理器的优势,并行执行多个任务。
- 实现异步编程:主线程可以在等待后台线程完成任务的同时,继续执行其他任务。
三、Java多线程的实现方式
1. 继承Thread类
通过继承
java.lang.Thread
类并重写其run
方法来实现多线程。这种方式简单直接,但存在Java单继承的限制。
public class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is running."); // 执行具体任务 } public static void main(String[] args) { MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); t1.start(); // 启动线程 t2.start(); // 启动线程 }
}
2. 实现Runnable接口
通过实现
java.lang.Runnable
接口的run
方法来创建线程。这种方式更为灵活,因为一个类可以实现多个接口,同时也可以通过Thread
类的构造器将Runnable
实例传递给线程。
public class MyRunnable implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is running."); // 执行具体任务 } public static void main(String[] args) { Thread t1 = new Thread(new MyRunnable()); Thread t2 = new Thread(new MyRunnable()); t1.start(); t2.start(); }
}
3. 实现Callable接口与Future
Callable
接口类似于Runnable
,但它可以返回一个结果,并且可以抛出异常。Callable
通常与Future
一起使用,Future
用于表示异步计算的结果。
import java.util.concurrent.*; public class MyCallable implements Callable<Integer> { @Override public Integer call() throws Exception { // 模拟耗时操作 Thread.sleep(1000); return 123; } public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(2); Future<Integer> future = executor.submit(new MyCallable()); System.out.println("Waiting for result..."); Integer result = future.get(); // 阻塞等待结果 System.out.println("Result: " + result); executor.shutdown(); }
}
四、线程的生命周期
线程的生命周期包括新建状态、就绪状态、运行状态、阻塞状态和死亡状态。
- 新建状态:线程被创建但尚未启动。
- 就绪状态:线程已准备好执行,但尚未获得CPU时间片。
- 运行状态:线程获得CPU时间片,正在执行。
- 阻塞状态:线程由于某种原因(如等待IO操作完成、等待锁资源等)暂停执行。
- 死亡状态:线程执行完毕或被强制终止,不再执行任何操作。
线程状态转换示例
线程的状态转换是线程执行过程中的自然流程。以下是一个简化的示例,用于说明线程状态之间的转换:
public class ThreadLifecycleExample { static class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is in RUNNABLE state."); synchronized (this) { try { wait(); // 进入WAITING状态 } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 恢复中断状态 } } System.out.println(Thread.currentThread().getName() + " resumes and terminates."); } } public static void main(String[] args) throws InterruptedException { MyThread t = new MyThread(); t.start(); // t进入RUNNABLE状态 // 假设主线程执行了一些操作后,决定唤醒t Thread.sleep(1000); // 模拟耗时操作 synchronized (t) { t.notify(); // 唤醒t,使其从WAITING状态进入RUNNABLE状态 } // t最终会执行完毕,进入TERMINATED状态 } } // 注意:上述代码中的wait()和notify()调用必须放在同步块中,否则将抛出IllegalMonitorStateException。 // 此外,由于wait()会释放锁,而notify()不会立即让线程进入RUNNABLE状态(需要CPU调度), // 因此实际输出可能因线程调度和JVM实现而有所不同。
在实际应用中,线程的状态转换远比上述示例复杂,特别是在多线程并发环境下,线程的调度和执行顺序往往难以预测。
五、同步与互斥
1. 同步的必要性
在多线程环境下,多个线程可能会同时访问共享资源(如内存中的变量、文件等),这可能导致数据不一致、脏读、脏写等问题。为了确保数据的一致性和完整性,需要对访问共享资源的操作进行同步控制。
2. Java中的同步机制
Java提供了多种同步机制,包括synchronized关键字、Lock接口及其实现(如ReentrantLock)、volatile关键字等。
synchronized关键字
- 同步方法:在方法声明中加上synchronized关键字,该方法在同一时刻只能被一个线程执行。
- 同步代码块:使用synchronized(Object lock) { ... }语法,对特定代码块进行同步,其中lock是锁对象。
public class Counter { private int count = 0; // 同步方法 public synchronized void increment() { count++; } // 同步代码块 public void incrementWithBlock(Object lock) { synchronized (lock) { count++; } }
}
Lock接口
Lock
接口提供了比synchronized关键字更灵活的锁定机制,它允许显式地获取和释放锁,以及尝试非阻塞地获取锁。
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(); // 显式释放锁 } }
}
volatile关键字
volatile关键字用于确保变量的可见性,即当一个线程修改了被volatile修饰的变量的值时,这个新值对其他线程是立即可见的。但volatile不能保证原子性,也不具备互斥性。
public class VolatileExample { private volatile boolean flag = false; public void setFlag(boolean flag) { this.flag = flag; } public boolean getFlag() { return flag; }
}
3. 同步的代价
同步虽然能够解决多线程并发带来的问题,但它也引入了额外的开销,如线程等待锁的时间、上下文切换的成本等。因此,在设计多线程程序时,应合理使用同步机制,避免过度同步导致的性能问题。
六、线程间通信的深入探索
在Java中,线程间通信主要依赖于共享内存和相应的同步机制。通过共享内存,线程可以访问和修改同一份数据,而同步机制则确保了在多线程环境下对这些数据的访问是安全且有序的。
1. 等待/通知机制
Java中的
wait()
和notify()
/notifyAll()
方法是实现线程间通信的经典方式。这些方法是Object
类的一部分,因此任何对象都可以作为锁来使用这些机制。
- wait():使当前线程等待,直到另一个线程调用此对象的
notify()
方法或notifyAll()
方法。调用wait()
方法时,当前线程必须持有该对象的锁。调用后,当前线程会释放锁并进入等待状态,直到被唤醒。- notify():唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的。
- notifyAll():唤醒在此对象监视器上等待的所有线程。
使用
wait()
和notify()
/notifyAll()
时,必须注意以下几点:
- 必须在同步方法或同步代码块中调用这些方法,因为它们依赖于对象锁。
- 调用
wait()
的线程会释放锁,并在等待期间无法继续执行。- 调用
notify()
或notifyAll()
的线程不会立即释放锁,直到它退出同步方法或同步代码块。wait()
、notify()
和notifyAll()
在调用时必须处理InterruptedException
异常。
2. Java并发包中的线程间通信
除了
wait()
和notify()
/notifyAll()
方法外,Java并发包(java.util.concurrent
)还提供了更高级的线程间通信机制,如BlockingQueue
、CountDownLatch
、CyclicBarrier
、Semaphore
等。
- BlockingQueue:支持两个附加操作的队列。这两个附加操作是:在元素从队列中取出时等待队列变为非空,以及在元素添加到队列中时等待队列中有可用空间。
BlockingQueue
接口是Java并发包中用于生产者-消费者问题的一种重要工具,它提供了一系列线程安全的队列操作。
BlockingQueue
的实现包括ArrayBlockingQueue
、LinkedBlockingQueue
、PriorityBlockingQueue
等。这些实现各有特点,比如ArrayBlockingQueue
是一个由数组支持的有界阻塞队列,LinkedBlockingQueue
是一个由链表结构组成的有界(但默认大小为Integer.MAX_VALUE
)或无界阻塞队列,而PriorityBlockingQueue
则是一个支持优先级排序的无界阻塞队列。
3. 其他并发工具
- CountDownLatch:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
- CyclicBarrier:一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点(common barrier point)。在涉及固定大小的线程组时,这些线程必须互相等待,直到所有线程都到达该屏障点,然后从屏障点继续执行。
- Semaphore:一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个
acquire()
,然后再获取该许可。每个release()
添加一个许可,从而可能释放一个正在acquire()
中阻塞的线程。这些工具各有用途,在解决复杂的并发问题时非常有用。例如,
CountDownLatch
可以用于等待一组任务的完成,CyclicBarrier
可以用于让一组线程在某个点互相等待然后共同继续执行,而Semaphore
则可以用于控制对共享资源的访问。
相关文章:
Java基础-Java多线程机制
(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 一、引言 二、多线程的基本概念 1. 线程与进程 2. 多线程与并发 3. 多线程的优势 三、Java多线程的实…...
MySQL技巧之跨服务器数据查询:基础篇-A数据库与B数据库查询合并--封装到存储过程中
MySQL技巧之跨服务器数据查询:基础篇-A数据库与B数据库查询合并–封装到存储过程中 我们的最终目的是什么?当然的自动执行这些合并操作! 上一篇 MySQL技巧之跨服务器数据查询:基础篇-A数据库与B数据库查询合并 我们已经知道怎么合…...
MATLAB向量元素的引用
我们定义一个向量后,如果想引用的话,可以通过索引 i n d ind ind来实现。 注意:MATLAB中向量的开始索引是1,与许多编程语言不同。 例如: 如果想引用多个的话,可以用索引 i n d ind ind来提取多个位置 例如…...
leetcode-44-通配符匹配
题解: 代码: 参考: (1)牛客华为机试HJ71字符串通配符 (2)leetcode-10-正则表达式匹配...
基于YOLOv8深度学习的智慧课堂学生专注度检测系统(PyQt5界面+数据集+训练代码)
本研究提出了一种基于YOLOv8深度学习的智慧课堂学生专注度检测系统,旨在实现对课堂中学生专注度的实时分析与评估。随着智慧教育的快速发展,学生的课堂表现和专注度成为评估学习效果的重要因素之一。然而,传统的专注度评估方法往往依赖于主观…...
vue项目使用eslint+prettier管理项目格式化
代码格式化、规范化说明 使用eslintprettier进行格式化,vscode中需要安装插件ESLint、Prettier - Code formatter,且格式化程序选择为后者(vue文件、js文件要分别设置) 对于eslint规则,在格式化时不会全部自动调整&…...
Java基础-组件及事件处理(中)
(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 BorderLayout布局管理器 说明: 示例: FlowLayout布局管理器 说明: …...
UNIX网络编程-TCP套接字编程(实战)
概述 TCP客户端/服务器程序示例是执行如下步骤的一个回射服务器: 客户端从标准输入读入一行文本,并写给服务器。服务器从网络输入读入这行文本,并回射给客户端。客户端从网络输入读入这行回射文本,并显示在标准输出上。 TCP服务器…...
python编写一个自动清理三个月以前的邮件脚本
以下是一个使用 Python 编写的自动清理三个月以前的邮件的脚本。这个脚本适用于连接支持 IMAP 协议的邮箱服务,例如 Gmail。请注意,在执行此操作时,您需要提供电子邮件账号和应用程序专用密码(建议不要使用普通密码,并…...
C++组合复用中,委托的含义与作用
委托(Delegation)的含义与作用 委托是一种软件设计技术,它允许一个对象在处理某个请求时,将请求的处理责任转移给另一个对象。委托的核心思想是通过组合(composition)而不是继承(inheritance&a…...
自制C++游戏头文件:C++自己的游戏头文件!!!(后续会更新)
引言 在这个数字时代,计算机游戏已经成为人们生活中不可或缺的一部分。它们不仅为我们带来了无尽的乐趣,还激发了我们的创造力和解决问题的能力。今天,我们将深入探讨一个特别的头文件——CPPgame.h,它包含了多个结构体和函数&am…...
java 读取 有时需要sc.nextLine();读取换行符 有时不需要sc.nextLine();读取换行符 详解
在 Java 中,使用 Scanner 类读取输入时,换行符的处理行为取决于所用的读取方法。不同方法的工作原理会影响是否需要额外调用 sc.nextLine() 来清理缓冲区中的换行符。 核心问题 根本原因:Scanner 是基于输入流工作的,而换行符&am…...
Redis知识分享(三)
目录 前言 七、事务管理 7.1事务中的异常处理 八、订阅发布 8.1概述 8.2.Redis针对发布订阅相关指令 九、主从复制 9.1主从复制概述 9.2.主从复制的用处 9.3主从复制实现原理 9.3.1.psync指令 9.3.2.复制偏移量 9.3.3复制积压缓冲区&节点ID 前言 今天…...
python安装包报错
多次安装均报错 ERROR: Could not find a version that satisfies the requirement win10toast ERROR: No matching distribution found for win10toast 然后还提示 WARNING: Retrying (Retry(total4, connectNone, readNone, redirectNone, statusNone)) after connectio…...
Linux性能优化之火焰图简介
Linux 火焰图(Flame Graph)是一种可视化工具,用于分析程序性能问题,尤其是 CPU 使用情况。它展示了程序中函数调用的层次结构和各个调用栈占用的时间比例。 以下是详细介绍,包括火焰图的工作原理、生成步骤和实际使用中…...
Unity类银河战士恶魔城学习总结(P129 Craft UI 合成面板UI)
【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili 教程源地址:https://www.udemy.com/course/2d-rpg-alexdev/ 本章节实现了合成面板的UI设置 UI_CraftWindow.cs 字段作用: UI 组件: itemName / itemDescription / icon&#…...
linux基础笔试练习题笔记(2)
在Linux系统上,下面那个命令不可以用来查看文件内容() A.cat B.ls C.less D.more 答案解析: cat命令用用于一次性显示文件的所有内容,一般文件内容较多时一般会使用more或less命令。 more:分页显示文件内容…...
Android OpenGL ES详解——glTexImage2D方法
glTexImage2D是OpenGL中的一个重要函数,其作用是为2D纹理分配显存并上传数据。以下是关于glTexImage2D作用的详细解释: 一、函数原型 在OpenGL ES 2.0中,glTexImage2D的函数原型如下: GL_APICALL void GL_APIENTRY glTexImage2…...
Redisson 中开启看门狗(watchdog)机制
在分布式系统中,分布式锁是一种常用的技术手段,用于确保在多个节点同时访问共享资源时的一致性和正确性。Redisson 是一个强大的 Java 分布式框架,它提供了丰富的分布式数据结构和服务,其中开启看门狗(watchdog&#x…...
【JSOO】设计模式
单例模式工厂模式状态模式观察者模式桥接模式 设计模式(是一种通过经验中总结出来的经过反复验证能够解决一类通用问题的可以反复重用的就可称它为模式,否则只能称为功能模块);模式:把解决问题的方法抽取出来ÿ…...
本草纲目数字化:Spring Boot在中药实验管理中的应用
1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管理中药实验管理系统的相关信息成为必然。开发…...
java八股-jvm入门-程序计数器,堆,元空间,虚拟机栈,本地方法栈,类加载器,双亲委派,类加载执行过程
文章目录 PC Register堆虚拟机栈方法区(Metaspace元空间双亲委派机制类加载器 类装载的执行过程 PC Register 程序计数器(Program Counter Register)是 Java 虚拟机(JVM)中的一个组件,它在 JVM 的内存模型中扮演着非常…...
重构Action-cli前端脚手架
一、概述 最近一年,为了满足公司业务开发,解决重复搭建项目繁琐过程,自己开发了一个前端脚手架,并发布到npm。随着时间的推移,发现之前的版本存在很多问题,有些功能做不到位,而且代码也不是很规…...
华为USG5500防火墙配置NAT
实验要求: 1.按照拓扑图部署网络环境,使用USG5500防火墙,将防火墙接口加入相应的区域,添加区域访问规则使内网trust区域可以访问DMZ区域的web服务器和untrust区域的web服务器。 2.在防火墙上配置easy-ip,使trust区域…...
【大数据学习 | HBASE高级】hive操作hbase
一般在查询hbase的数据的时候我们可以直接使用hbase的命令行或者是api进行查询就行了,但是在日常的计算过程中我们一般都不是为了查询,都是在查询的基础上进行二次计算,所以使用hbase的命令是没有办法进行数据计算的,并且对于hbas…...
集群聊天服务器(9)一对一聊天功能
目录 一对一聊天离线消息服务器异常处理 一对一聊天 先新添一个消息码 在业务层增加该业务 没有绑定事件处理器的话消息会派发不出去 聊天其实是服务器做一个中转 现在同时登录两个账号 收到了聊天信息 再回复一下 离线消息 声明中提供接口和方法 张三对离线的李…...
《FreeRTOS列表和列表项篇》
FreeRTOS列表和列表项 1. 什么是列表和列表项?1.1 列表list1.2 列表项list item 2. 列表和列表项的初始化2.1 列表的初始化2.2 列表项的初始化 3. 列表项的插入4. 列表项末尾插入5. 列表项的删除6. 列表的遍历 列表和列表项是FreeRTOS的一个数据结构,是F…...
C++:哈希拓展-位图
目录 一.问题导入 二.什么是位图? 2.1如何确定目标数在哪个比特位? 2.2如何存放高低位 2.3位图模拟代码实现 2.3.1如何标记一个数 2.3.2如何重置标记 2.3.3如何检查一个数是否被标记 整体代码实现 标准库的Bitset 库中的bitset的缺陷 简单应用 一.问题导入 这道…...
【数据结构与算法】查找
文章目录 一.查找二.线性结构的查找2.1顺序查找2.2折半查找2.3分块查找 三.树型结构的查找3.1二叉排序树1.定义2.二叉排序树的常见操作3.性能分析 3.2平衡二叉树1.定义2.平衡二叉树的常见操作3.性能分析 3.3B树1.定义2.B树的相关操作 3.4B树1.定义2.B树与B树的比较 四.散列表1.…...
从零开始学习 sg200x 多核开发之 milkv-duo256 编译运行 sophpi
sophpi 是 算能官方针对 sg200x 系列的 SDK 仓库 https://github.com/sophgo/sophpi ,支持 cv180x、cv81x、sg200x 系列的芯片。 SG2002 简介 SG2002 是面向边缘智能监控 IP 摄像机、智能猫眼门锁、可视门铃、居家智能等多项产品领域而推出的高性能、低功耗芯片&a…...
中国第八冶金建设公司网站/网站top排行榜
更多内容请查看:BizTalk动手实验系列目录 BizTalk 开发系列 BizTalk 的TCP/IP适配器最初是为英国的保健行业开发。该适配器属于BizTalk进程内适配器,将消息通过TCP/IP 套接字符串在BizTalk服务器与远程客户端间进行通讯。 TCP/IP适配器支持以下几种交互模…...
什么是推广型网站/关键词营销优化
...
免费建站自助建站网站建设教程网站建设教程/网址提交百度
这里我们再理解了AJAX后,开始来用实例感受AJAX的力量。今天我最后要实现的效果,当鼠标放到图片上时会根据,会把数据库库里的数据读出,通过显示框显示出来。这个在很多网上商店都有用到这里效果,我们这里用AJAX来实现这…...
建设企业展示网站/婚恋网站排名前10
iBatis是一个基于SQL映射支持Java和NET的持久层框架,相对Hibernate和ApacheOJB等“一站式”ORM解决方案而言,iBatis 是一种“半自动化”的ORM实现。一、JAR包依赖ibatis-2.3.4.726.jarmysql-connector-java-5.0.8-bin.jar二、SqlMap.propertiesdrivercom…...
广西建设工程质量检测试验协会网站/湖南网站制作公司
<body> <div class"fd_0"> <div class"fd_1"> <table> <tr> <td> <p>博看文思是三星移动全球三大核心开发商之一(亚洲唯一一家);也是法国电信(Ora…...
做金融网站拘留多久/重庆小潘seo
从目前的政策环境来讲,送货机器人比送货无人机能更快实现落地。 本月月初,弗吉尼亚州通过法案,允许地面送货机器人上路,。同样关于送货机器人,爱达荷州(位于美国西北部)于昨天也批准其上路&…...