秋招Java后端开发冲刺——并发篇1(线程与进程、多线程)

一、进程

1. 进程
进程是程序的一次动态执行过程,是操作系统资源分配的基本单位。
2. 进程和线程的区别

特性进程线程
定义独立运行的程序实例,资源分配的基本单位进程中的一个执行单元,CPU调度的基本单位
资源进程拥有独立的内存空间和资源线程共享进程的堆和方法区(JDK1.8之后为元空间)
通信进程间通信(IPC)较为复杂线程间通信(共享内存)较为简单
开销创建和销毁进程开销较大创建和销毁线程开销较小
独立性进程之间相对独立线程间相互影响
并发性进程可以并发执行线程可以并发执行
调度由操作系统调度由操作系统或线程库调度
崩溃影响一个进程崩溃不会影响其他进程一个线程崩溃可能会影响整个进程

3. 进程和线程的联系

联系描述
组成关系一个进程可以包含一个或多个线程,线程是进程的一部分,多个线程共享进程的资源。
资源共享线程共享进程的堆和方法区(JDK1.8之后为元空间)、文件句柄等资源,进程则有自己的独立资源。
并发执行进程和线程都可以并发执行,利用多核 CPU 提高程序的并行度。
调度进程和线程都由操作系统进行调度,多线程程序中,线程的调度可以由 JVM 和操作系统共同管理。

二、线程

1. Java线程

  • JDK 1.2 之前,Java 线程是基于绿色线程(Green Threads)实现的,这是一种用户级线程(用户线程);JDK1.2之后Java线程是基于原生线程(Native Threads,操作系统内核线程)实现。
  • 虚拟机栈和本地方法栈线程私有是为了保证局部变量不被其他线程访问
  • 程序技术器线程私有是为了线程切换后能找到上次运行的位置继续执行

2. 线程的创建方式

  • 继承Thread类并重写 run 方法来定义线程的执行逻辑。
public class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread is running");}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();  // 启动线程}
}
  • 实现Runable接口并将其实例传递给 Thread 对象
public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Runnable is running");}public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();  // 启动线程}
}
  • 实现Callable接口并使用 FutureTask 包装 Callable 对象,然后将其传递给 Thread 对象(Callable 可以有返回值,且可以抛出异常
public class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {return "Callable is running";}public static void main(String[] args) {MyCallable callable = new MyCallable();FutureTask<String> futureTask = new FutureTask<>(callable);Thread thread = new Thread(futureTask);thread.start();  // 启动线程try {// 获取执行结果String result = futureTask.get();System.out.println(result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}
}
  • 其他方式:使用线程池、使用CompletableFuture类

3. 线程(Thread类)的常见方法

方法名描述
void start()启动线程,调用线程的 run 方法
void run()线程的执行方法,需要重写
void interrupt()中断线程
boolean isInterrupted()测试线程是否已经中断
static boolean interrupted()测试当前线程是否已经中断,并清除当前线程的中断状态
void join()等待线程终止
void join(long millis)等待线程终止最长时间为 millis 毫秒
void join(long millis, int nanos)等待线程终止最长时间为 millis 毫秒加 nanos 纳秒
static void sleep(long millis)使当前线程睡眠(暂停执行)指定的毫秒数
static void sleep(long millis, int nanos)使当前线程睡眠(暂停执行)指定的毫秒数加纳秒数
void setPriority(int newPriority)更改线程的优先级
int getPriority()返回线程的优先级
void setName(String name)更改线程名称
String getName()返回线程名称
long getId()返回线程的唯一标识符
Thread.State getState()返回线程的状态
boolean isAlive()测试线程是否还活着
static void yield()暂停当前正在执行的线程对象,并执行其他线程
static Thread currentThread()返回对当前正在执行的线程对象的引用
static int activeCount()返回当前线程的线程组中活动线程的数目
static void dumpStack()将当前线程的堆栈跟踪打印到标准错误流
StackTraceElement[] getStackTrace()返回一个数组,表示该线程的堆栈转储
static boolean holdsLock(Object obj)当且仅当当前线程在指定的对象上保持监视器锁时,返回 true
void setDaemon(boolean on)将该线程标记为守护线程或用户线程
boolean isDaemon()测试该线程是否为守护线程
void checkAccess()判断当前运行的线程是否有权限修改此线程
ThreadGroup getThreadGroup()返回该线程所属的线程组

4. 线程的生命周期

  • New (新建状态):线程对象被创建,但还未调用 start() 方法。
  • Runnable (就绪状态):start() 方法被调用,线程进入就绪状态,等待 CPU 时间片的分配。
  • Running (运行状态):线程获得 CPU 时间片,开始执行 run() 方法中的代码。
  • Blocked (阻塞状态):线程因等待资源或锁而进入阻塞状态,无法继续执行。
  • Waiting (等待状态):线程等待另一个线程显式地唤醒自己,通过 wait()、join() 或 sleep() 等方法进入等待状态。
  • Timed Waiting (计时等待状态):线程等待一定时间后会被自动唤醒,通过 sleep(long millis)、wait(long timeout) 或 join(long millis) 等方法进入计时等待状态。
  • Terminated (终止状态):线程运行结束或因异常退出 run() 方法,线程进入终止状态
    以下是线程生命周期的图解:
    (1)JDK1.5之前

    (2)JDK1.5之后
    在这里插入图片描述

三、多线程

1. 线程安全问题的解决方式

(1)产生原因

  • 共享资源:多个线程同时访问和修改同一资源,例如变量、对象、文件等。
  • 缺乏同步:线程在访问共享资源时,没有正确使用同步机制,导致多个线程同时执行对共享资源的操作。
  • 原子性操作的缺乏:对共享资源的操作需要分多个步骤完成,如果这些步骤不能保证原子性,会导致线程安全问题。
  • 可见性问题:一个线程对共享资源的修改,其他线程不能立即看到,导致数据不一致。
  • 指令重排序:编译器和处理器为了优化性能,可能会对指令进行重排序,导致线程安全问题

(2)解决方式

  • Synchronized关键字:同步块可以确保在同一时间只有一个线程执行同步代码,从而避免多个线程同时访问共享资源的问题。(详解请参考)
public class SynchronizedExample {public synchronized void synchronizedMethod() {// 同步实例方法// 其他线程不能同时执行此方法}public static synchronized void staticSynchronizedMethod() {// 同步静态方法// 其他线程不能同时执行此静态方法}public void synchronizedBlock() {synchronized (this) {// 同步代码块// 锁定当前实例对象}}
}
  • Lock锁:是 Java 提供的一种显式锁机制,有多种锁类型实现。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class LockExample {private final Lock lock = new ReentrantLock();public void lockMethod() {lock.lock();try {// 临界区代码// 其他线程不能同时执行此代码} finally {lock.unlock();}}
}
  • 使用线程本地变量 (ThreadLocal):每个线程都有自己的变量副本,互不干扰。
public class ThreadLocalExample {private ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);public void increment() {threadLocal.set(threadLocal.get() + 1);}public int get() {return threadLocal.get();}
}
  • Atomic Variables(原子变量):java.util.concurrent.atomic 包提供了多种原子变量,如 AtomicInteger、AtomicLong、AtomicReference 等,它们提供了一种无锁的线程安全机制。
import java.util.concurrent.atomic.AtomicInteger;public class AtomicExample {private final AtomicInteger counter = new AtomicInteger(0);public void increment() {counter.incrementAndGet();}public int getCounter() {return counter.get();}
}

(3) Synchronized 和 Lock 的区别

特性synchronizedLock
实现内置语言特性通过 java.util.concurrent.locks 包提供
锁的释放自动释放:线程退出同步代码块或方法时自动释放需要显式调用 unlock() 方法
灵活性灵活性较低,只能锁定方法或代码块灵活性较高,可以尝试获取锁、定时获取锁等
锁的获取线程阻塞式等待支持阻塞式、非阻塞式、定时尝试获取锁
性能较低:适用于简单的同步较高:适用于复杂的并发控制
条件变量提供 Condition 类,支持多个条件变量
中断响应不支持线程中断支持线程中断,响应中断请求
读写锁不支持支持,通过 ReentrantReadWriteLock 实现
公平锁不支持支持公平锁,通过 ReentrantLock 实现

2. 死锁
多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。

(1)死锁的产生:四个必要条件

  • 非抢占式:线程已获得的资源在未使用完之前不能被其他线程强行剥夺
  • 循环等待:若干线程之间形成一种头尾相接的循环等待资源关系
  • 互斥条件:该资源任意一个时刻只由一个线程占用
  • 请求与保持条件:个线程因请求资源而阻塞时,对已获得的资源保持不放

(2)死锁的预防:破坏必要条件

  • 破坏请求与保持条件:一次性申请所有的资源(会造成内存开销极大,因为程序可能很长一段时间使用不到该资源)。
  • 破坏非抢占式条件:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
  • 破坏循环等待条件:按某一顺序申请资源,释放资源则反序释放。

(3)死锁的避免

  • 在资源分配时,借助于算法(比如银行家算法)对资源分配进行计算评估,使其进入安全状态。
  • 安全状态:系统能够按照某种线程推进顺序(P1、P2、P3……Pn)来为每个线程分配所需资源,直到满足每个线程对资源的最大需求,使每个线程都可顺利完成。
  • 银行家算法代码实现
import java.util.Arrays;public class BankersAlgorithm {private int numProcesses;private int numResources;private int[] available;private int[][] maximum;private int[][] allocation;private int[][] need;public BankersAlgorithm(int numProcesses, int numResources) {this.numProcesses = numProcesses;this.numResources = numResources;this.available = new int[numResources];this.maximum = new int[numProcesses][numResources];this.allocation = new int[numProcesses][numResources];this.need = new int[numProcesses][numResources];}public void setAvailable(int[] available) {System.arraycopy(available, 0, this.available, 0, numResources);}public void setMaximum(int process, int[] max) {System.arraycopy(max, 0, this.maximum[process], 0, numResources);for (int j = 0; j < numResources; j++) {this.need[process][j] = this.maximum[process][j] - this.allocation[process][j];}}public void setAllocation(int process, int[] alloc) {System.arraycopy(alloc, 0, this.allocation[process], 0, numResources);for (int j = 0; j < numResources; j++) {this.need[process][j] = this.maximum[process][j] - this.allocation[process][j];}}public boolean requestResources(int process, int[] request) {// Step 1: Check if request <= needfor (int j = 0; j < numResources; j++) {if (request[j] > need[process][j]) {return false; // Request exceeds need}}// Step 2: Check if request <= availablefor (int j = 0; j < numResources; j++) {if (request[j] > available[j]) {return false; // Request exceeds available resources}}// Step 3: Pretend to allocate requested resourcesfor (int j = 0; j < numResources; j++) {available[j] -= request[j];allocation[process][j] += request[j];need[process][j] -= request[j];}// Step 4: Check system safetyif (checkSafety()) {return true; // Safe state, allocation is successful} else {// Revert allocation if not safefor (int j = 0; j < numResources; j++) {available[j] += request[j];allocation[process][j] -= request[j];need[process][j] += request[j];}return false; // Not a safe state}}private boolean checkSafety() {boolean[] finish = new boolean[numProcesses];int[] work = Arrays.copyOf(available, numResources);while (true) {boolean foundProcess = false;for (int i = 0; i < numProcesses; i++) {if (!finish[i]) {boolean canAllocate = true;for (int j = 0; j < numResources; j++) {if (need[i][j] > work[j]) {canAllocate = false;break;}}if (canAllocate) {for (int j = 0; j < numResources; j++) {work[j] += allocation[i][j];}finish[i] = true;foundProcess = true;}}}if (!foundProcess) {break;}}for (boolean f : finish) {if (!f) {return false; // System is not in a safe state}}return true; // System is in a safe state}public static void main(String[] args) {int numProcesses = 5;int numResources = 3;BankersAlgorithm ba = new BankersAlgorithm(numProcesses, numResources);ba.setAvailable(new int[]{10, 5, 7});ba.setMaximum(0, new int[]{7, 5, 3});ba.setMaximum(1, new int[]{3, 2, 2});ba.setMaximum(2, new int[]{9, 0, 2});ba.setMaximum(3, new int[]{2, 2, 2});ba.setMaximum(4, new int[]{4, 3, 3});ba.setAllocation(0, new int[]{0, 1, 0});ba.setAllocation(1, new int[]{2, 0, 0});ba.setAllocation(2, new int[]{3, 0, 2});ba.setAllocation(3, new int[]{2, 1, 1});ba.setAllocation(4, new int[]{0, 0, 2});int[] request = {1, 0, 2};int process = 1;boolean success = ba.requestResources(process, request);System.out.println("Request " + (success ? "granted" : "denied"));}
}

3. 线程池
(1)核心参数

  • 核心线程数 (corePoolSize):线程池中保持活动的最小线程数量,即使这些线程处于空闲状态。
  • 最大线程数 (maximumPoolSize):线程池中允许的最大线程数量。当任务队列已满且已达到核心线程数时,线程池会创建新的线程来处理任务,直到达到最大线程数。达到最大线程数后,新任务将被拒绝处理,并根据饱和策略进行处理。
  • 空闲线程存活时间 (keepAliveTime):当线程池中线程数量超过核心线程数时,多余的空闲线程在等待新任务时的最长存活时间。超过这个时间的空闲线程将被终止和移除,直到线程池中的线程数量等于核心线程数。
  • 时间单位 (unit):空闲线程存活时间的单位,如秒、毫秒等。与 keepAliveTime 参数一起使用。
  • 任务队列 (workQueue):用于保存等待执行任务的阻塞队列。常用的队列实现有:
    • 直接提交队列 (SynchronousQueue):不保存任务,每个插入操作必须等待相应的删除操作。
    • 有界队列 (ArrayBlockingQueue):有固定容量的队列,当队列满时,插入操作将被阻塞。
    • 无界队列 (LinkedBlockingQueue):队列大小没有上限,理论上可以无限制地增加队列长度。
    • 优先队列 (PriorityBlockingQueue):按任务优先级排序的无界队列。
  • 线程工厂 (threadFactory):用于创建新线程的工厂。通过自定义线程工厂,可以为每个新线程设置名称、优先级等属性。
  • 拒绝策略 (handler):当任务队列已满且线程池中的线程数量已达到最大线程数时,如何处理新任务。Java 提供了四种预定义的拒绝策略:
    • AbortPolicy(默认):抛出 -
    • RejectedExecutionException,拒绝任务。
    • CallerRunsPolicy:由调用线程处理该任务。
    • DiscardPolicy:丢弃无法处理的任务,不予处理。
    • DiscardOldestPolicy:丢弃最早添加到队列中的任务,然后尝试重新提交新任务。

(2)线程池创建

  • 固定大小的线程池 (Fixed Thread Pool)
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
  • 单线程化的线程池 (Single Thread Executor)
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
  • 缓存的线程池 (Cached Thread Pool)
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
  • 定时任务线程池 (Scheduled Thread Pool)
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);

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

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

相关文章

ubuntu安装miniconda、jupyer、ros2

miniconda: 类似于虚拟机 ,可以安装不同版本的python jupyer: python执行、调试命令工具 1.下载安装文件 wget https://repo.anaconda.com/miniconda/Miniconda3-py310_23.5.2-0-Linux-x86_64.sh 2.安装minconda bash https://repo.anaconda.com/miniconda/Miniconda3-py…

傅雷家书思维导图的制作方法,分享制作技巧和软件!

在浩如烟海的书海中&#xff0c;《傅雷家书》以其独特的视角和深厚的情感&#xff0c;成为了无数读者心中的经典。那么&#xff0c;如何将这部饱含父爱的书信集转化为清晰易懂的思维导图呢&#xff1f;本文将为您详细解读傅雷家书思维导图的制作技巧&#xff0c;并推荐几款实用…

能自动铲屎的养猫救星?带你了解热门爆款智能猫砂盆的真实体验!

在谈论猫咪的日常生活时&#xff0c;我和朋友最经常聊的话题就是在各种各样的紧急情况下如何狼狈地赶回去给猫咪铲屎&#xff0c;毕竟猫砂盆里的屎但凡停留那么几小时&#xff0c;就要开始发臭了&#xff0c;一下班回去实在受不了那个味道&#xff0c;每次下班在家门口都想带个…

gemma2 vllm和ollama推理部署;openai接口调用、requests调用

参考: https://huggingface.co/google/gemma-2-9b https://ai.google.dev/gemma/docs/model_card_2?hl=zh-cn https://huggingface.co/blog/gemma2 发布了两个型号9B\27B 支持上下文长度有点短:4096 1、 ollama推理部署 升级ollama: curl -fsSL https://ollama.com/…

修改Springboot项目名称

修改Springboot项目名称 1. 整体描述2. 具体步骤2.1 修改module名称2.2 修改程序包名2.3 mybatis/mybatis-plus配置修改2.4 logback文件2.5 yml配置2.6 Application启动类2.7 其他 3. 总结 1. 整体描述 开发过程中&#xff0c;经常遇到新来个项目&#xff0c;需要一份初始代码…

【前端】HTML+CSS复习记录【5】

文章目录 前言一、padding、margin、border&#xff08;边框边距&#xff09;二、样式优先级三、var&#xff08;使用 CSS 变量更改多个元素样式&#xff09;四、media quary&#xff08;媒体查询&#xff09;系列文章目录 前言 长时间未使用HTML编程&#xff0c;前端知识感觉…

去中心化革命:探索区块链技术的前沿

随着信息技术的飞速发展&#xff0c;区块链技术作为一种新兴的去中心化解决方案&#xff0c;正逐渐改变着我们的经济、社会和技术格局。本文将从区块链的基本原理、当前的应用实例以及未来的发展趋势三个方面&#xff0c;深入探讨区块链技术在革命性变革中的角色和影响。 1. 区…

TypeScript中,如何利用数组生成一个联合类型

本文由 ChatMoney团队出品 在开发中我们常常会遇到这样一个问题&#xff0c;代码如下&#xff1a; const arr ["a","b","c","d","e","f","g","h","i","j","k&quo…

【信息学奥赛】CSP-J/S初赛06 信息编码(ASCLL码及汉字信息编码)

本专栏&#x1f449;CSP-J/S初赛内容主要讲解信息学奥赛的初赛内容&#xff0c;包含计算机基础、初赛常考的C程序和算法以及数据结构&#xff0c;并收集了近年真题以作参考。 如果你想参加信息学奥赛&#xff0c;但之前没有太多C基础&#xff0c;请点击&#x1f449;专栏&#…

51单片机点亮第一个LED灯

欢迎入群共同学习交流 时间记录&#xff1a;2024/7/2 一、电路原理图 二、代码程序 1.项目代码结构 2.主程序代码 #include <reg51.h>sbit ledP1^0;void delay(int ms) {int i0;while(ms--){for(i0;i<110;i);} }int main() {while(1){led 1;delay(1000);led 0;d…

git 禁止dev合并到任何其他分支

创建 pre-merge-commit 钩子 导航到 Git 仓库的钩子目录&#xff1a; cd /path/to/your/repo/.git/hooks创建或编辑 pre-merge-commit 钩子&#xff1a; 也可以通过指令创建 nano pre-merge-commit在钩子文件中添加以下代码&#xff1a; #!/bin/sh# 获取当前分支名称 curr…

矮油,希喂、喜崽、爱立方主食冻干是超贵的进口平替?最新测评

相信很多铲屎官一到选粮就苦恼&#xff0c;尤其是主食冻干&#xff0c;虽说主食冻干对猫咪的好处是普通猫粮无法比的&#xff0c;其价格也是远超普通猫粮的。所以很多铲屎官就很担心&#xff0c;花了高价买的主食冻干却营养不高。其实除了营养还有更多需要考虑的&#xff0c;比…

VBA提取word表格内容到excel

这是一段提取word表格中部分内容的vb代码。 Sub 提取word表格() mypath ThisWorkbook.Path & "\"myname Dir(mypath & "*.doc*")n 4 index of rowsRange("A1:F1") Array("课程代码", "课程名称", "专业&…

Linux miniconda 安装tensorflow-gpu遇到找不到GPU问题

背景&#xff1a; Linux Miniconda python3.9 安装步骤 1、 pip install tensorflow-gpu2.8.0 -i https://pypi.tuna.tsinghua.edu.cn/simple 2、报错如下&#xff1a; 更换镜像源&#xff0c;单独安装 pip install tf-estimator-nightly2.8.0.dev2021122109 -i https:/…

主从同步binlog

主从同步的原理是怎样的 提到主从同步的原理&#xff0c;我们就需要了解在数据库中的一个重要日志文件&#xff0c;那就是 Binlog 二 进制日志&#xff0c;它记录了对数据库进行更新的事件。实际上主从同步的原理就是基于 Binlog 进 行数据同步的。在主从复制过程中&#xff…

SpringBoot 项目整合 MyBatisPlus 框架,附带测试示例

文章目录 一、创建 SpringBoot 项目二、添加 MyBatisPlus 依赖三、项目结构和数据库表结构四、项目代码1、application.yml2、TestController3、TbUser4、TbUserMapper5、TestServiceImpl6、TestService7、TestApplication8、TbUserMapper.xml9、MyBatisPlusTest 五、浏览器测试…

网安小贴士(3)网安协议

一、前言 网络安全协议是构建安全网络环境的基础&#xff0c;它们帮助保护网络通信免受各种威胁和攻击。 二、定义 网络安全协议是指在计算机网络中用于确保网络通信和数据传输安全的协议。它们定义了在网络通信过程中的安全机制、加密算法、认证和授权流程等&#xff0c;以保…

为什么 [] == ![] 为 true?

&#x1f9d1;‍&#x1f4bb; 写在开头 点赞 收藏 学会&#x1f923;&#x1f923;&#x1f923; 前言 面试官问我&#xff0c;[] ![] 的结果是啥&#xff0c;我&#xff1a;蒙一个true&#xff1b; 面试官&#xff1a;你是对的&#xff1b;我&#xff1a;内心非常高兴&a…

继承QAbstractListModel,结合QListView

这里想要写一个QAbstractListModel的子类&#xff0c;学习一下如何实例化QAbstractListModel。 QAbstractListModel子类化-CSDN博客 QVariant与自定义类型互转之奇巧淫技_qt 类型转 qvariant-CSDN博客 #pragma once#include <QStyledItemDelegate> #include <qmeta…

Python:Pycharm安装指南

三、Pycharm安装指南 在开始之前今天内容之前&#xff0c;将上篇的初体验练习题公布如下&#xff1a; 初体验练习题&#xff1a;输入两个字符&#xff0c;将他们组合后输出。 str1 input("请输入名字&#xff1a;") str2 input("请输入城市&#xff1a;&qu…