Java 线程详解 --线程概念、线程池、线程同步与安全机制

一、Java线程的概念

Java 线程的本质:每个线程对应一个操作系统线程,由操作系统调度。JVM 通过调用操作系统 API(如 Linux 的 pthread)创建线程。

关键点
用户态与内核态:线程调度依赖操作系统(内核级线程),能直接利用多核 CPU。
线程生命周期:新建 → 就绪 → 运行 → 阻塞 → 终止。
JVM 线程模型:每个 Java 线程对应一个 Thread 对象,通过 start() 触发操作系统线程的创建。


二、线程的使用方法

方式 1:继承 Thread 类(简单但不够灵活)
class MyThread extends Thread {@Overridepublic void run() {System.out.println("线程执行: " + Thread.currentThread().getName());}
}// 使用
MyThread t = new MyThread();
t.start(); // 注意:必须调用 start(),而不是直接 run()
方式 2:实现 Runnable 接口(推荐,避免单继承限制)
class MyTask implements Runnable {@Overridepublic void run() {System.out.println("任务执行: " + Thread.currentThread().getName());}
}// 使用
Thread t = new Thread(new MyTask());
t.start();
方式 3:带返回值的 Callable(适合需要结果的任务)

Callable:带返回值的任务(像“下单”),比如 Callable<String> 表示这个任务最终会返回一个 String
Future:代表异步任务的“凭证”(像“订餐小票”),凭它未来可以取结果。

以订餐流程举例:

  1. 提交任务:你去餐厅点了一份炒饭,服务员给你一张小票Future)。
  2. 后厨做菜:厨师(线程池中的线程)开始炒饭(执行 Callable)。
  3. 等待结果:你可以干其他事情(不阻塞主线程),也可以随时拿小票问:“好了没?”(future.isDone())。
  4. 取回结果:当炒饭做好后,凭小票取餐(future.get() 拿到返回值)。

Future底层实现原理:

  1. 状态跟踪Future 内部维护任务状态:
    未完成:任务还在执行。
    已完成:任务正常结束,保存返回值。
    已取消:任务被中断。
    异常结束:保存抛出的异常。

  2. 阻塞获取:当调用 future.get() 时:
    • 如果任务已完成 → 直接返回结果。
    • 如果未完成 → 当前线程阻塞等待,直到任务完成(内部通过 wait/notify 机制实现)。

  3. 结果存储:任务完成后,返回值(或异常)会被存入 Future 内部的成员变量,供后续读取。

代码示例:

import java.util.concurrent.*;public class FutureExample {public static void main(String[] args) throws Exception {// 1. 创建线程池(后厨)ExecutorService executor = Executors.newSingleThreadExecutor();// 2. 提交 Callable 任务(下单炒饭)Future<String> future = executor.submit(new Callable<String>() {@Overridepublic String call() throws Exception {Thread.sleep(2000); // 模拟炒饭需要2秒return "扬州炒饭做好了!";}});System.out.println("提交任务后,主线程继续做其他事情...");// 3. 检查是否完成(非阻塞)if (future.isDone()) {System.out.println("任务已经完成!");} else {System.out.println("任务还在进行中...");}// 4. 阻塞获取结果(类似等待取餐)String result = future.get(); // 这里会阻塞,直到任务完成System.out.println("取到结果:" + result);executor.shutdown(); // 关闭线程池(后厨下班)}
}

输出:

提交任务后,主线程继续做其他事情...
任务还在进行中...
(等待2秒后)
取到结果:扬州炒饭做好了!
  1. 异常处理
    如果任务中抛出异常,future.get() 会抛出 ExecutionException,可通过 getCause() 获取原始异常:
try {future.get();
} catch (ExecutionException e) {System.out.println("任务出错:" + e.getCause());
}
  1. 超时控制
    避免无限等待,可以设置超时时间:
String result = future.get(3, TimeUnit.SECONDS); // 最多等3秒
  1. 取消任务
    如果不想等了,可以取消任务:
future.cancel(true); // true表示尝试中断正在执行的任务

三、Java 线程池机制详解

线程池的核心思想

复用线程:避免频繁创建/销毁线程的开销(类似餐厅固定几个服务员服务所有顾客,而不是每来一个顾客就雇佣新服务员)。
资源管控:通过队列缓冲任务,防止系统过载(类似餐厅的等候区,避免人太多挤爆店面)。


线程池的四大核心参数
ThreadPoolExecutor(int corePoolSize,      // 核心线程数(常驻员工)int maximumPoolSize,   // 最大线程数(临时工上限)long keepAliveTime,    // 空闲线程存活时间(临时工多久没活就解雇)TimeUnit unit,         // 时间单位BlockingQueue<Runnable> workQueue, // 任务队列(等候区座位数)RejectedExecutionHandler handler   // 拒绝策略(人满时怎么处理新顾客)
)

参数详解:

  1. corePoolSize:核心线程即使空闲也不会被销毁(除非设置 allowCoreThreadTimeOut)。
  2. maximumPoolSize:当队列满时,允许创建的最大线程数(核心线程 + 临时线程)。
  3. workQueue:常用队列类型:
    ArrayBlockingQueue:有界队列(固定容量)。
    LinkedBlockingQueue:无界队列(默认 Integer.MAX_VALUE,慎用易内存溢出)。
    SynchronousQueue:不存储任务,直接移交(适合瞬时高并发)。
  4. 拒绝策略(当队列和线程池全满时):
    AbortPolicy:抛异常(默认)。
    CallerRunsPolicy:让提交任务的线程自己执行。
    DiscardPolicy:默默丢弃新任务。
    DiscardOldestPolicy:丢弃队列最旧的任务,再尝试提交。

合理设置线程数
CPU密集型:线程数 ≈ CPU核数(避免过多上下文切换)。
IO密集型:线程数 ≈ CPU核数 * 2(或更高,因线程常阻塞在IO)。

监控线程池状态

// 查看活跃线程数
int activeCount = executor.getActiveCount(); 
// 查看任务队列大小
int queueSize = executor.getQueue().size();

线程池的工作流程
                ↗ 核心线程有空 → 立即执行
任务提交 → 检查核心线程↘ 核心线程忙 → 入队列 → 队列满? → 否 → 等待↘ 是 → 创建临时线程 → 超过最大数? → 是 → 拒绝

常用线程池(通过 Executors 工厂创建)
1. FixedThreadPool(固定大小团队)
ExecutorService fixedPool = Executors.newFixedThreadPool(4); // 4个核心线程

特点:核心线程=最大线程,无临时线程,使用无界队列(LinkedBlockingQueue)。
适用场景:已知并发量且任务耗时较长(如后台计算)。

2. CachedThreadPool(弹性团队)
ExecutorService cachedPool = Executors.newCachedThreadPool(); 

特点:核心线程=0,最大线程=Integer.MAX_VALUE,空闲线程60秒回收,使用 SynchronousQueue(直接移交任务)。
适用场景:短时高频小任务(如HTTP请求处理)。

3. SingleThreadExecutor(单人团队)
ExecutorService singlePool = Executors.newSingleThreadExecutor();

特点:核心线程=最大线程=1,无界队列,保证任务顺序执行。
适用场景:需要顺序执行的任务(如日志写入)。

4. ScheduledThreadPool(计划任务团队)
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2);
// 延迟3秒执行
scheduledPool.schedule(() -> System.out.println("Run after 3s"), 3, TimeUnit.SECONDS);
// 固定频率执行(每隔1秒)
scheduledPool.scheduleAtFixedRate(() -> System.out.println("Run every 1s"), 0, 1, TimeUnit.SECONDS);

特点:支持定时、周期性任务。
适用场景:心跳检测、定时数据同步。


5. 自定义线程池
public class ThreadPoolDemo {public static void main(String[] args) {// 创建线程池:2核心线程,5最大线程,10容量队列,拒绝策略抛异常ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 60, TimeUnit.SECONDS,new ArrayBlockingQueue<>(10),new ThreadPoolExecutor.AbortPolicy());// 提交20个任务(测试队列满时的扩容)for (int i = 0; i < 20; i++) {final int taskId = i;try {executor.submit(() -> {System.out.println("任务 " + taskId + " 由线程 " + Thread.currentThread().getName() + " 执行");try { Thread.sleep(1000); } catch (InterruptedException e) {}});} catch (RejectedExecutionException e) {System.out.println("任务 " + taskId + " 被拒绝!");}}executor.shutdown(); // 平滑关闭(等待已有任务完成)}
}

输出分析
• 前2个任务由核心线程立即执行。
• 接下来的10个任务进入队列。
• 当队列满后(10个),创建3个临时线程(总线程数=5)。
• 第18个任务提交时,线程数已达最大(5),队列满(10),触发拒绝策略抛异常。

场景推荐线程池参数要点
长期稳定并发任务FixedThreadPool核心线程数=最大线程数,队列容量适中
短期突发小任务CachedThreadPool注意防止无限创建线程(适合可控的短任务)
单线程顺序执行SingleThreadExecutor替代手动创建线程,保证顺序性
定时/周期性任务ScheduledThreadPool指定延迟和周期
高并发自定义需求ThreadPoolExecutor根据业务特点调整核心参数

线程池关闭方法
  1. shutdown():平滑关闭,不再接受新任务,等待已有任务完成。
  2. shutdownNow():立刻停止所有任务,返回未执行的任务列表。
List<Runnable> unfinishedTasks = executor.shutdownNow();

四、线程同步与安全,原理、用法及示例

在多线程环境下,当多个线程同时访问共享资源(如变量、文件、数据库)时,可能导致数据不一致或逻辑错误。线程同步的目的是协调线程间的执行顺序,确保线程安全。

详细参考:https://blog.csdn.net/gengzhikui1992/article/details/147230900?spm=1001.2014.3001.5501

常见同步方式及底层原理
1. synchronized 关键字:

原理:基于对象的内置锁(Monitor),每个对象关联一个Monitor。
执行synchronized代码时,线程需获取对象的Monitor锁:
• 成功则持有锁,执行代码。
• 失败时线程进入锁的等待队列(EntrySet),阻塞等待唤醒。
用法

// 同步方法
public synchronized void safeMethod() { /* ... */ }// 同步代码块
public void someMethod() {synchronized (this) { // 锁对象为当前实例// 临界区代码}
}

示例

class Counter {private int count = 0;public synchronized void increment() {count++; // 原子操作}
}

解析synchronized确保同一时刻仅一个线程执行increment()方法。


2. ReentrantLock 可重入锁:

原理:基于AQS(AbstractQueuedSynchronizer),维护一个CLH队列管理等待线程。
支持可重入性(同一线程可多次加锁)和公平性(可选)。
用法

private final ReentrantLock lock = new ReentrantLock();public void safeMethod() {lock.lock();  // 手动加锁try {// 临界区代码} finally {lock.unlock(); // 必须手动释放}
}

示例(带超时):

if (lock.tryLock(1, TimeUnit.SECONDS)) { // 尝试1秒内获取锁try { /* ... */ } finally { lock.unlock(); }
} else { // 超时处理 }

优势:比synchronized更灵活,支持尝试锁、公平锁等。

特性synchronizedReentrantLock
锁的获取方式自动获取和释放(JVM管理)手动 lock()unlock()(需写finally)
可中断性不支持(阻塞时无法中断)支持 lockInterruptibly()
超时机制不支持(只能阻塞等待)支持 tryLock(timeout)
公平锁仅非公平锁支持公平和非公平(构造参数控制)
条件变量只能绑定一个条件(wait()/notify()可创建多个条件(newCondition()
性能JDK6后优化后性能接近高并发竞争时性能更好
代码复杂度简单(自动管理)复杂(需手动释放,易忘)
锁的可见性通过JVM内存模型保证基于AQS的volatile变量保证

synchronized 的优势:简单、安全、自动释放锁,适合快速开发。
ReentrantLock 的优势:灵活、功能强大,适合需要超时、中断、公平锁等复杂场景。

最终建议:优先用 synchronized,遇到它无法满足需求时再考虑 ReentrantLock


3. volatile 变量:

多线程环境下,变量操作可能引发两种问题:

  1. 可见性问题:A线程修改了变量,B线程看不到最新值。
  2. 原子性问题:看似一步的操作(如 i++),实际分三步(读-改-写),中间可能被其他线程打断。

volatile 变量:解决了可见性问题,原理:通过内存屏障禁止指令重排序,确保变量的修改对所有线程立即可见(不保证原子性)。

强制读写主内存volatile 变量修改后,其他线程立即可见。
禁止指令重排序:确保代码执行顺序符合预期。

使用场景
适合做 状态标志(如开关控制),不涉及复杂计算。

public class Server {private volatile boolean isRunning = true;  // 状态标志public void stop() {isRunning = false;  // 修改后,其他线程立即可见}public void run() {while (isRunning) {  // 循环读取最新值// 处理请求...}}
}

局限性
不保证原子性volatile 无法解决 i++ 这种非原子操作的问题。

volatile int count = 0;
count++;  // 实际分三步:读 -> 改 -> 写(线程不安全!)

4. 原子类(Atomic Classes):解决原子性问题

封装原子操作:通过 CPU 的 CAS(Compare-And-Swap) 指令,保证操作的原子性。
无需加锁:性能优于 synchronized

常见类
AtomicIntegerAtomicLong:整型原子操作。
AtomicReference:对象引用原子操作。
AtomicStampedReference:解决 ABA 问题(版本号控制)。

使用场景
适合 计数器累加器 等需要原子操作的场景。

public class Counter {private AtomicInteger count = new AtomicInteger(0);public void increment() {count.incrementAndGet();  // 原子自增}public int get() {return count.get();}
}

示例:AtomicReference 保证对象引用原子性

public class AtomicReferenceDemo {private AtomicReference<String> latestMessage = new AtomicReference<>("");public void updateMessage(String message) {latestMessage.set(message);  // 原子更新引用}public String getMessage() {return latestMessage.get();}
}

示例:解决 ABA 问题(AtomicStampedReference)

public class ABADemo {private AtomicStampedReference<Integer> atomicValue = new AtomicStampedReference<>(100, 0);  // 初始值100,版本号0public void update() {int[] stampHolder = new int[1];int currentValue = atomicValue.get(stampHolder);  // 获取值和版本号int newValue = currentValue + 1;atomicValue.compareAndSet(currentValue, newValue, stampHolder[0], stampHolder[0] + 1);}
}
特性volatile原子类(如 AtomicInteger)
解决可见性问题✔️(强制主内存读写)✔️(内部使用 volatile 变量)
解决原子性问题❌(如 i++ 仍不安全)✔️(封装原子操作)
性能高(无锁)高(CAS 无锁)
适用场景状态标志、开关控制计数器、累加器、复杂原子操作
ABA 问题无法解决可通过 AtomicStampedReference 解决

volatile 是轻量级的可见性解决方案,不保证原子性
• 原子类通过 CAS 实现无锁原子操作,同时解决可见性和原子性
• 两者性能均优于锁,但适用场景不同,不要混淆!

  1. volatile
    • 变量被多个线程共享,但只有一个线程修改它。
    • 需要立即可见性,但不涉及复合操作(如 i++)。
    • 典型场景:状态标志(boolean 开关)。

  2. 用原子类
    • 变量被多个线程频繁修改(如计数器)。
    • 需要原子性操作(如 addAndGet()compareAndSet())。
    • 典型场景:并发计数器、无锁数据结构。

  3. synchronizedReentrantLock
    • 需要同步多步操作(如先读后写)。
    • 原子类和 volatile 无法满足复杂逻辑时。


6. 读写锁 ReentrantReadWriteLock

想象一个图书馆:
读锁:允许多个人同时读书(共享资源)。
写锁:当有人要修改书的内容时,必须清场(独占资源),其他人不能读也不能写。

核心规则

  1. 读锁之间不互斥:多个线程可以同时持有读锁。
  2. 写锁与其他锁互斥:写锁生效时,其他线程不能获取读锁或写锁。
  3. 写锁优先:如果写锁在等待,新来的读锁会被阻塞(防止“写线程饥饿”)。

为什么用读写锁?
读多写少 的场景下(如缓存系统、配置管理),用读写锁比普通互斥锁(如 synchronized)性能更高:
读操作:允许多线程并发读取。
写操作:保证独占修改,避免数据不一致。

场景:实现一个线程安全的缓存系统

public class Cache<K, V> {private final Map<K, V> cacheMap = new HashMap<>();private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();private final Lock readLock = rwLock.readLock();   // 读锁private final Lock writeLock = rwLock.writeLock(); // 写锁// 读操作:允许多线程并发读public V get(K key) {readLock.lock();try {return cacheMap.get(key);} finally {readLock.unlock();}}// 写操作:独占访问public void put(K key, V value) {writeLock.lock();try {cacheMap.put(key, value);} finally {writeLock.unlock();}}// 复杂操作:先读后写(需要先释放读锁,再获取写锁)public void updateIfPresent(K key, V newValue) {readLock.lock();try {if (cacheMap.containsKey(key)) {// 释放读锁,获取写锁(注意:不能直接升级锁!)readLock.unlock();writeLock.lock();try {cacheMap.put(key, newValue);} finally {writeLock.unlock();}// 重新获取读锁(如果需要)readLock.lock();}} finally {readLock.unlock();}}
}

关键细节

  1. 避免锁升级:先释放读锁,再获取写锁。
  2. 写锁优先:如果写锁在等待,后续读锁会被阻塞(可通过公平锁缓解)。
  3. 锁的释放:必须用 try-finally 确保释放,否则会导致死锁。

在持有写锁时,可以获取读锁,然后释放写锁(保持数据可见性):

public void writeThenRead() {writeLock.lock();try {// 修改数据...readLock.lock();  // 锁降级(允许)} finally {writeLock.unlock();}try {// 读取数据...} finally {readLock.unlock();}
}

不能直接从读锁升级到写锁(会导致死锁):

public void readThenWrite() {readLock.lock();try {// 如果发现需要修改数据...writeLock.lock();  // 错误!会阻塞,因为读锁未释放,其他线程也无法释放写锁} finally {readLock.unlock();}
}

线程同步方式的对比与选择
方式原理适用场景性能
synchronized对象内置锁简单同步,少量竞争中等,自动释放锁
ReentrantLockAQS队列锁复杂控制(如超时、公平锁)高,需手动释放
volatile内存可见性单变量状态标志极高,无锁
原子类CAS指令计数器,单变量原子操作高,无锁竞争
ReentrantReadWriteLock读写分离锁读多写少场景读高,写中等
  1. 优先选择高级工具:如java.util.concurrent包下的并发集合(ConcurrentHashMap, BlockingQueue)。
  2. 避免锁粒度过大:尽量缩小同步范围,减少竞争。
  3. 资源释放:使用Lock时务必在finally中释放锁。
  4. 分工协作:读写分离时使用ReentrantReadWriteLock提升性能。
  5. 监测工具:利用jstackVisualVM排查死锁和性能瓶颈。

五、Java线程安全集合详解

Java提供了多种线程安全的集合类,适用于高并发场景。它们通过内部优化(如分段锁、写时复制)实现高效并发,避免开发者手动加锁。以下是常见线程安全集合及其使用场景和示例:


1. ConcurrentHashMap(并发哈希表)

原理:将数据分为多个段(Segment,Java 8后改为Node数组+CAS),每个段独立加锁。允许多线程同时读写不同段的数据。
适用场景:高并发键值存储(如缓存、计数器)。
示例

ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();// 线程安全的插入(若key不存在)
map.putIfAbsent("apple", 1);// 原子累加操作
map.compute("apple", (k, v) -> v == null ? 1 : v + 1);// 遍历(弱一致性迭代器,不抛ConcurrentModificationException)
map.forEach((k, v) -> System.out.println(k + ": " + v));

2. CopyOnWriteArrayList(写时复制列表)

原理:写操作时复制整个数组(加锁保证原子性),读操作无锁。适合读多写少的场景。
适用场景:监听器列表、配置信息列表。
示例

CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("user1");// 读操作无需加锁
for (String user : list) {System.out.println(user);
}// 写操作会复制新数组
list.add("user2"); // 原数组:[user1],新数组:[user1, user2]

3. BlockingQueue(阻塞队列)

原理:当队列空时阻塞消费者,队列满时阻塞生产者。内部通过ReentrantLockCondition实现。
常见实现
ArrayBlockingQueue:有界队列(数组实现)。
LinkedBlockingQueue:可选有界或无界(链表实现)。
PriorityBlockingQueue:优先级阻塞队列。
适用场景:生产者-消费者模型。
示例

BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);// 生产者
new Thread(() -> {try {queue.put("task1"); // 队列满时阻塞} catch (InterruptedException e) {e.printStackTrace();}
}).start();// 消费者
new Thread(() -> {try {String task = queue.take(); // 队列空时阻塞System.out.println("处理任务: " + task);} catch (InterruptedException e) {e.printStackTrace();}
}).start();

4. ConcurrentLinkedQueue(并发链表队列)

原理:基于无锁算法(CAS),实现非阻塞线程安全队列。
适用场景:高并发非阻塞队列(如任务分发)。
示例

ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();// 生产者
queue.offer(100); // 非阻塞添加// 消费者
Integer value = queue.poll(); // 非阻塞取出

5. ConcurrentSkipListMap(并发跳表映射)

原理:基于跳表(Skip List)数据结构,实现有序的并发Map。
适用场景:需要排序的高并发键值存储(如排行榜)。
示例

ConcurrentSkipListMap<Integer, String> rank = new ConcurrentSkipListMap<>();
rank.put(90, "Alice");
rank.put(85, "Bob");// 按分数从高到低遍历
rank.descendingMap().forEach((score, name) -> {System.out.println(name + ": " + score);
});

6. CopyOnWriteArraySet(写时复制集合)

原理:基于CopyOnWriteArrayList实现,用数组存储元素,写操作时复制。
适用场景:读多写少的集合(如IP白名单)。
示例

CopyOnWriteArraySet<String> ips = new CopyOnWriteArraySet<>();
ips.add("192.168.1.1");// 检查IP是否存在(无需加锁)
if (ips.contains("192.168.1.1")) {System.out.println("IP允许访问");
}

7. Collections.synchronizedXXX(同步包装类)

原理:通过包装普通集合,对所有方法加synchronized锁。
适用场景:低并发环境(性能低于专用并发集合)。
示例

List<String> syncList = Collections.synchronizedList(new ArrayList<>());// 遍历时需手动加锁
synchronized (syncList) {for (String item : syncList) {System.out.println(item);}
}

线程安全集合对比表
集合名称原理适用场景性能特点
ConcurrentHashMap分段锁/CAS高并发键值存储高吞吐量,低延迟
CopyOnWriteArrayList写时复制读多写少的列表写操作慢,读操作快
BlockingQueue锁+条件队列生产者-消费者模型阻塞操作,适用于任务调度
ConcurrentLinkedQueue无锁(CAS)高并发非阻塞队列高并发,无锁
ConcurrentSkipListMap跳表有序并发键值存储查询和插入O(log n)
CopyOnWriteArraySet基于CopyOnWriteArrayList读多写少的集合CopyOnWriteArrayList
  1. 键值存储
    • 高并发写入:ConcurrentHashMap
    • 需要排序:ConcurrentSkipListMap

  2. 列表/集合
    • 读多写少:CopyOnWriteArrayList/CopyOnWriteArraySet
    • 写操作频繁:使用ConcurrentHashMap模拟(如Collections.newSetFromMap

  3. 队列
    • 阻塞队列:ArrayBlockingQueue/LinkedBlockingQueue
    • 非阻塞队列:ConcurrentLinkedQueue

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

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

相关文章

PCL 计算点云至平面距离(SIMD加速)

文章目录 一、简介二、实现代码三、实现效果一、简介 SIMD 是一种并行计算模型,其中“单指令”表示处理器在同一时刻执行相同的指令,而“多数据”则表示同一条指令操作多个数据元素(如数组中的多个元素或矩阵中的多个元素)。与传统的串行计算不同,SIMD 能够同时处理多个数…

Ubuntu 22.04 完美安装 ABAQUS 教程:从零到上手,解决兼容问题

教程概述与安装准备 本教程详细介绍了在 Ubuntu 22.04 系统上安装 ABAQUS 2023 及 ifort 2021 的步骤,并实现用户子程序的链接。教程同样适用于 ABAQUS 2021(需相应调整文件名和路径)以及 Ubuntu 18.04 至 22.04 系统,尽管未在所有版本上测试。需要注意的是,Intel 的 One…

Spark-TTS(Text-to-Speech):基于大语言模型的语音合成革新者!!!

Spark-TTS&#xff1a;基于大语言模型的语音合成革新者 &#x1f680; &#xff08;全称解析 核心特性 行业影响全解读&#xff09; 一、概念定义与技术定位 1. 英文全称 Spark-TTS: An Efficient LLM-Based Text-to-Speech Model • 关键词解析&#xff1a; • LLM-Based…

2025年十六届蓝桥杯Python B组原题及代码解析

相关试题可以在洛谷上测试用例&#xff1a; 2025 十六届 蓝桥杯 Python B组 试题 A&#xff1a;攻击次数 答案&#xff1a;103 print(103)代码&#xff1a; # 初始化敌人的血量 x 2025# 初始化回合数 turn 0# 模拟攻击过程 while x > 0:# 回合数加一turn 1# 第一个英…

Spring Boot项目中结合MyBatis实现MySQL的自动主从切换

原理解析 1. MySQL主从复制&#xff08;Master-Slave Replication&#xff09; 工作原理&#xff1a;MySQL主从复制通过二进制日志&#xff08;binary log&#xff09;来同步数据。主服务器记录所有更改操作到二进制日志中&#xff0c;从服务器读取这些日志并执行相应的SQL语…

【经验记录贴】使用配置文件提高项目的可维护性

mark一下。 整体修改前后如下&#xff1a; 课题&#xff1a; 在项目中有一个支持的文件类型的FILE_TYPE的定义&#xff0c; 这个是写死在主程序中&#xff0c;每次增加可以支持的文件类型的时候&#xff0c;都需要去修改主程序中这个FILGE_TYPE的定义。 主程序修改其实不太花时…

用DeepSeek AI高效制作专业PPT

在当今职场中,制作精美而有力的PPT是展示想法、汇报工作和赢得机会的关键技能。然而,许多人花费过多时间在格式调整和内容组织上,而非专注于核心信息的传达。DeepSeek AI作为新一代智能助手,能够帮助您将PPT制作效率提升300%,同时显著提高专业度。本文将详细介绍如何利用D…

【AI学习从零至壹】语⾔模型及词向量相关知识

语⾔模型及词向量相关知识 ⾃然语⾔处理简介⾃然语⾔理解&#xff08;NLU&#xff09;⾃然语⾔⽣成&#xff08;NLG&#xff09;发展趋势信息检索技术布尔检索与词袋模型基于相关性的检索 / TF-IDF举例&#xff1a; 语⾔模型 / Language Model神经⽹络语⾔模型Word2Vec训练⽅法…

15.【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--单体转微服务--如何拆分单体

单体应用&#xff08;Monolithic Application&#xff09;是指将所有功能模块集中在一个代码库中构建的应用程序。它通常是一个完整的、不可分割的整体&#xff0c;所有模块共享相同的运行环境和数据库。这种架构开发初期较为简单&#xff0c;部署也较为方便&#xff0c;但随着…

在ARM架构Mac上部署Python 3.12与Conda环境的全链路指南!!!

在ARM架构Mac上部署Python 3.12与Conda环境的全链路指南 &#x1f680; &#xff08;M1/M2芯片实测&#xff5c;含性能调优避坑手册&#xff09; &#x1f31f; 核心价值点 • 原生ARM支持&#xff1a;突破Rosetta转译的性能损耗 • 环境隔离&#xff1a;Conda虚拟环境管理多…

yml文件上传并映射到实体类

文章目录 功能背景功能需要前端开发组件选用组件嵌套和参数绑定上传逻辑示例 后端开发接收逻辑解析逻辑省流纯手动实现&#xff08;不建议&#xff09; 功能背景 开发一个配置文件解析功能&#xff0c;需要兼容老版本的配置文件。 功能需要 前端&#xff1a;两个配置文件分别…

ElasticSearch中常用的数据类型

一、映射 Elasticsearch中通过映射来指定字段的数据类型&#xff0c;映射方式有2种&#xff0c;静态映射和动态映射。 1.动态映射 使用动态映射时&#xff0c;无须指定字段的数据类型&#xff0c;Elasticshearch会自动根据字段内容来判断映射到哪个数据类型。 比如&#xff…

【神经网络结构的组成】深入理解 转置卷积与转置卷积核

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;《深度学习理论直觉三十讲》_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 …

CSS高度坍塌?如何解决?

一、什么是高度坍塌&#xff1f; 高度坍塌&#xff08;Collapsing Margins&#xff09;是指当父元素没有设置边框&#xff08;border&#xff09;、内边距&#xff08;padding&#xff09;、内容&#xff08;content&#xff09;或清除浮动时&#xff0c;其子元素的 margin 会…

Web前端开发——格式化文本与段落(上)

一、学习目标 网页内容的排版包括文本格式化、段落格式化和整个页面的格式化&#xff0c;这是设计个网页的基础。文本格式化标记分为字体标记、文字修饰标记。字体标记和文字修饰标记包括对于字体样式的一些特殊修改。段落格式化标记分为段落标记、换行记、水平分隔线标记等。…

关于PHP开源CMS系统ModStart的详细介绍及使用指南

关于PHP开源CMS系统ModStart的详细介绍及使用指南&#xff1a; &#x1f50d; ModStart是什么&#xff1f; 基于Laravel框架开发的模块化CMS系统采用Apache 2.0 开源协议&#xff0c;完全免费可商用特别适合需要快速搭建企业级网站/管理系统的开发者 &#x1f680; 核心优势…

TCP标志位抓包

说明 TCP协议的Header信息&#xff0c;URG、ACK、PSH、RST、SYN、FIN这6个字段在14字节的位置&#xff0c;对应的是tcp[13]&#xff0c;因为字节数是从[0]开始数的&#xff0c;14字节对应的就是tcp[13]&#xff0c;因此在抓这几个标志位的数据包时就要明确范围在tcp[13] 示例1…

RK3588S开发板将SPI1接口改成GPIO

参考官方教程&#xff1a;ROC-RK3588S-PC 一.基本知识&#xff1a; 1.GPIO引脚计算&#xff1a; ROC-RK3588S-PC 有 5 组 GPIO bank&#xff1a;GPIO0~GPIO4&#xff0c;每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分&#xff0c;常用以下公式计算引脚&#xff1a;GPIO…

Java 设计模式:适配器模式详解

Java 设计模式&#xff1a;适配器模式详解 适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它通过将一个类的接口转换为客户端期望的另一个接口&#xff0c;使原本不兼容的类能够协同工作。适配器模式就像现实生活中的电源适配器&#xf…

python manimgl数学动画演示_微积分_线性代数原理_ubuntu安装问题[已解决]

1.背景 最近调研python opencv, cuda加速矩阵/向量运算, 对于矩阵的线性变换, 秩, 转秩, 行列式变化等概概念模糊不清. 大概课本依旧是天书, 于是上B站搜索线性代数, 看到 3Blue1Brown 线性变换本质 视频, 点击观看. 惊为天人 --> 豁然开朗 --> 突然顿悟 --> 开心不已…