Java 多线程编程:提升系统并发处理能力!
多线程是 Java 中实现并发任务执行的关键技术,能够显著提升程序在多核处理器上的性能以及处理多任务的能力。本文面向初级到中级开发者,从多线程的基本定义开始,逐步讲解线程创建、状态管理、同步机制、并发工具以及新兴的虚拟线程技术。每部分都配有详细的代码示例,帮助读者理解并实践 Java 多线程编程。
什么是多线程?
多线程是指在同一程序中同时运行多个执行流,每个执行流称为一个线程。在 Java 中,线程由 Thread
类或其子类表示,每个线程独立执行特定的任务。通过 Thread.currentThread()
方法,可以获取当前正在运行的线程对象及其信息,例如线程名称。多线程的主要优势在于充分利用 CPU 的多核特性,通过并行执行任务提高程序的吞吐量和响应速度。例如,在 Web 服务器中,每个用户请求可以分配一个线程处理,从而实现高并发的请求处理能力。
创建多线程的三种基本方式
Java 提供了多种创建线程的方式,每种方法适用于不同的场景。以下是三种常见实现及其代码示例:
-
继承
Thread
类通过继承
Thread
类并重写run()
方法,可以直接定义线程的行为。调用start()
方法启动线程后,JVM 会执行run()
中的逻辑。public class ThreadDemo {public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread();thread.start();} }class MyThread extends Thread {public void run() {System.out.println("Thread running: " + Thread.currentThread().getName());} }
-
实现
Runnable
接口实现
Runnable
接口并将其传递给Thread
对象,是一种更灵活的方式。这种方法将任务逻辑与线程对象分离,符合接口优先的设计原则,常用于需要复用任务逻辑的场景。public class ThreadDemo {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new MyRunnable());thread.start();} }class MyRunnable implements Runnable {public void run() {System.out.println("Runnable running: " + Thread.currentThread().getName());} }
-
使用
Callable
和Future
Callable
接口允许线程执行完成后返回结果,结合Future
对象可以获取异步任务的返回值。通常与线程池搭配使用,适用于需要计算结果并进一步处理的场景。public class ThreadDemo {public static void main(String[] args) throws InterruptedException {ExecutorService executor = Executors.newSingleThreadExecutor();Future<String> future = executor.submit(new MyCallable());System.out.println(future.get()); // 阻塞获取结果executor.shutdown();} }class MyCallable implements Callable<String> {public String call() {return "Result from thread: " + Thread.currentThread().getName();} }
对于初学者,建议从 Runnable
开始学习,因其简单且易于扩展。中级开发者可以探索 Callable
,结合线程池实现更复杂的异步任务。
线程的状态与管理
Java 中的线程在其生命周期中会经历多种状态,这些状态由 JVM 管理并反映线程的当前执行情况:
- 新建(New):线程对象已创建,但未调用
start()
方法。 - 运行(Runnable):调用
start()
后,线程进入可运行状态,等待 CPU 调度。 - 阻塞(Blocked):线程尝试获取锁但被其他线程占用,进入阻塞队列。
- 等待(Waiting):通过
wait()
、join()
等方法进入等待状态,需其他线程唤醒。 - 超时等待(Timed Waiting):通过
sleep()
或wait(timeout)
设置有限等待时间。 - 终止(Terminated):线程执行完毕或异常退出。
线程管理涉及以下关键操作:
- 中断:调用
thread.interrupt()
发送中断信号,线程可通过isInterrupted()
检查状态并响应。通常用于优雅地终止线程。 - 守护线程:调用
thread.setDaemon(true)
将线程标记为守护线程。当所有非守护线程结束时,JVM 会退出,无论守护线程是否完成。常用于日志记录或监控等后台任务。
线程同步与锁机制
当多个线程同时访问共享资源时,可能导致数据不一致或竞争条件。Java 提供了多种锁机制来确保线程安全,每种机制适用于不同的并发场景。以下通过一个示例学校布告栏详细展示这些机制。
示例场景
在 Java 多线程环境中,多个学生(读线程)同时查看布告栏,而一个老师(写线程)更新布告栏,这种场景涉及读写并发问题。下面介绍几种 Java 常见的同步机制,并给出相应的代码示例。
1. synchronized
(独读独写,不可中断)
synchronized
是 Java 中最基本的同步机制,通过锁住对象或代码块,确保同一时间只有一个线程可以访问受保护的资源。
原理: synchronized
使用对象锁来实现同步。每个对象都有一个与之关联的锁,当线程进入 synchronized
代码块或方法时,它会尝试获取对象的锁。如果获取成功,线程将继续执行;否则,线程将被阻塞,直到其他线程释放锁。
使用场景
老师写布告栏时,学生不能读且排队等待获取锁;学生读取时,老师不能写且排队等待获取锁。
代码示例
class BulletinBoard {private String message = "Initial Message";// 读方法:只有一个线程读取public synchronized String read() {return message;}// 写方法:只有一个线程可以写public synchronized void write(String newMessage) {System.out.println(Thread.currentThread().getName() + " 正在写入布告栏...");message = newMessage;System.out.println(Thread.currentThread().getName() + " 写入完成: " + message);}
}public class SynchronizedExample {public static void main(String[] args) {BulletinBoard board = new BulletinBoard();// 启动多个学生线程(读)for (int i = 0; i < 5; i++) {new Thread(() -> {System.out.println(Thread.currentThread().getName() + " 读取到消息: " + board.read());}, "学生" + i).start();}// 启动老师线程(写)new Thread(() -> {board.write("New Announcement");}, "老师").start();}
}
特点
synchronized
适合简单场景,但读写都需要加锁,会影响读性能(读操作不能并发)。synchronized
简单但不够灵活,读和写操作互斥,学生之间也不能并发读,效率较低。
2. ReentrantLock
(独读独写,可中断)
ReentrantLock
是一个可重入锁,它提供比 synchronized
更灵活的锁机制,比如尝试锁、超时等待、可中断锁等。
原理: ReentrantLock
实现了 Lock
接口,提供了 lock()
和 unlock()
方法来获取和释放锁。它支持可重入性,即同一个线程可以多次获取同一个锁。
使用场景
老师写布告栏时锁定,学生读时也需要锁定,但可以用更细粒度的控制,如尝试获取锁。
代码示例
import java.util.concurrent.locks.ReentrantLock;class BulletinBoardLock {private String message = "Initial Message";private final ReentrantLock lock = new ReentrantLock(); // 创建重入锁public String read() {lock.lock(); // 加锁try {return message;} finally {lock.unlock(); // 释放锁}}public void write(String newMessage) {lock.lock();try {System.out.println(Thread.currentThread().getName() + " 正在写入布告栏...");message = newMessage;System.out.println(Thread.currentThread().getName() + " 写入完成: " + message);} finally {lock.unlock();}}
}public class ReentrantLockExample {public static void main(String[] args) {BulletinBoardLock board = new BulletinBoardLock();for (int i = 0; i < 5; i++) {new Thread(() -> System.out.println(Thread.currentThread().getName() + " 读取到消息: " + board.read()), "学生" + i).start();}new Thread(() -> board.write("Updated Announcement"), "老师").start();}
}
特点
ReentrantLock
需要手动加锁、解锁,容易出错。仍然是独占锁,读操作不能并发,影响性能。- ReentrantLock 比 synchronized 更灵活,但仍未解决读读并发问题,需要手动管理锁。
3. ReentrantReadWriteLock(多读独写)
ReadWriteLock
提供读锁和写锁,允许多个读线程并发访问,但写线程独占资源。适合读多写少的场景。
原理:ReadWriteLock
维护一对锁:读锁和写锁。读锁允许多个线程同时获取,写锁只允许一个线程获取。当线程获取读锁时,其他线程可以继续获取读锁,但不能获取写锁;当线程获取写锁时,其他线程都不能获取读锁或写锁。
使用场景
多个学生可以同时读布告栏,但老师不能写;老师写时,所有学生不能读。
代码示例
import java.util.concurrent.locks.ReentrantReadWriteLock;class BulletinBoardRW {private String message = "Initial Message";private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();// 读操作(多个线程可以并发执行)public String read() {rwLock.readLock().lock();try {return message;} finally {rwLock.readLock().unlock();}}// 写操作(只有一个线程能执行)public void write(String newMessage) {rwLock.writeLock().lock();try {System.out.println(Thread.currentThread().getName() + " 正在写入布告栏...");message = newMessage;System.out.println(Thread.currentThread().getName() + " 写入完成: " + message);} finally {rwLock.writeLock().unlock();}}
}public class ReadWriteLockExample {public static void main(String[] args) {BulletinBoardRW board = new BulletinBoardRW();for (int i = 0; i < 5; i++) {new Thread(() -> System.out.println(Thread.currentThread().getName() + " 读取到消息: " + board.read()), "学生" + i).start();}new Thread(() -> board.write("Updated Announcement"), "老师").start();}
}
特点
- 允许多个读线程并发,提高读性能。但写操作会阻塞所有读操作。
- ReadWriteLock 允许多个学生并发读,提高效率,但写操作仍需独占。
4. StampedLock
(乐观读独写)
StampedLock
是 Java 8 引入的优化读写锁,支持乐观读(无锁读)性能更高,但使用更复杂。
原理: StampedLock
维护一个邮戳(stamp),用于表示锁的状态。线程在读取共享资源时,可以先尝试获取乐观读邮戳,如果验证通过,则读取成功;否则,线程需要获取悲观读锁。
使用场景
多个学生可以乐观读布告栏(假设内容不常变),老师写时仍需锁定。
代码示例
import java.util.concurrent.locks.StampedLock;class BulletinBoardStamped {private String message = "Initial Message";private final StampedLock lock = new StampedLock();public String read() {long stamp = lock.tryOptimisticRead();String result = message;if (!lock.validate(stamp)) { // 检查是否有写入发生stamp = lock.readLock();try {result = message;} finally {lock.unlockRead(stamp);}}return result;}public void write(String newMessage) {long stamp = lock.writeLock();try {System.out.println(Thread.currentThread().getName() + " 正在写入布告栏...");message = newMessage;System.out.println(Thread.currentThread().getName() + " 写入完成: " + message);} finally {lock.unlockWrite(stamp);}}
}
特点
- 乐观读锁在没有写入的情况下提高读取效率。
- 适用于读多写少的场景。
5. volatile
(保证单一变量的可见性)
volatile
是 Java 中的关键字,用于保证单一变量的可见性。当一个线程修改了被 volatile
修饰的变量的值,其他线程能够立即看到最新的值。
volatile
关键字会强制线程在修改共享变量后立即将值刷新到主内存,并在其他线程读取该变量时强制它们从主内存读取最新的值。
volatile 确保变量的可见性,但不提供互斥性。适用于只有一个线程写,多个线程读的场景。
使用场景
老师更新布告栏内容,学生直接读取最新内容,无需锁。
class BulletinBoardVolatile {private volatile String content = "初始内容"; // volatile 保证可见性public void write(String newContent) {System.out.println("[老师] 开始更新(volatile)...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}content = newContent;System.out.println("[老师] 已更新内容:" + content);}public String read() {System.out.println(Thread.currentThread().getName() + " 读取内容(volatile):" + content);return content;}
}
public class VolatileExample{public static void main(String[] args) {BulletinBoard board = new BulletinBoard();new Thread(() -> board.write("讲座通知"), "Teacher").start();for (int i = 1; i <= 3; i++) {new Thread(() -> {while (true) { // 持续监听变化board.read();try { Thread.sleep(300); } catch (InterruptedException e) {}}}, "Student-"+i).start();}}}
特点
- 适用于简单变量的同步,但不能保证原子性(多个变量或复杂逻辑需要加锁)。
6. Semaphore
(控制访问数量)
如果需要限制同时访问的读线程数,可以使用 Semaphore
。
Semaphore 是信号量,用于控制同时访问资源的线程数量。
使用场景
限制同时读布告栏的学生数量(如最多 5个学生),老师写时独占。
import java.util.concurrent.Semaphore;class BulletinBoardSemaphore {private String content = "初始内容";private final Semaphore semaphore = new Semaphore(3); // 允许3个并发读public void write(String newContent) throws InterruptedException {semaphore.acquire(3); // 获取所有许可try {System.out.println("[老师] 开始更新(Semaphore)...");Thread.sleep(1000);content = newContent;System.out.println("[老师] 已更新内容:" + content);} finally {semaphore.release(3);}}public String read() throws InterruptedException {semaphore.acquire();try {System.out.println(Thread.currentThread().getName() + " 开始读取(Semaphore)...");Thread.sleep(500);System.out.println(Thread.currentThread().getName() + " 读取内容:" + content);return content;} finally {semaphore.release();}}
}public class SemaphoreExpamle{public static void main(String[] args) {BulletinBoardSemaphore board = new BulletinBoardSemaphore();new Thread(() -> {try { board.write("考试注意事项"); } catch (InterruptedException e) { e.printStackTrace(); }}, "Teacher").start();for (int i = 1; i <= 5; i++) {new Thread(() -> {try { board.read(); } catch (InterruptedException e) { e.printStackTrace(); }}, "Student-"+i).start();}}
}
特点
- 适用于限制并发访问数的场景。
总结
同步机制 | 读性能 | 写性能 | 特点 |
---|---|---|---|
synchronized | 低 | 低 | 简单易用,自动释放锁,但无法中断等待 |
ReentrantLock | 低 | 低 | 可中断、可设置超时,需要手动释放锁 |
ReadWriteLock | 高 | 低 | 读写分离,提高读多写少场景的性能 |
StampedLock | 最高 | 低 | 支持乐观读,减少锁竞争,适合读远多于写的场景 |
volatile | 最高 | 高 | 仅保证可见性,不保证原子性,适合简单状态标志 |
Semaphore | 可控 | 低 | 控制并发线程数量,适合资源池或限流场景 |
选择合适的机制可以大幅提升系统的并发性能和可扩展性!
并发发集合 concurrent
在多线程环境下,普通的集合类(如 ArrayList
、HashMap
等)不是线程安全的。如果多个线程同时修改这些集合,可能会导致数据不一致或抛出 ConcurrentModificationException
异常。为了解决这个问题,Java 提供了 java.util.concurrent
包,其中包含了一系列线程安全的并发集合类。。以下是常见接口及其实现对比:
接口 | 非线程安全 | 线程安全 |
---|---|---|
List | ArrayList | CopyOnWriteArrayList |
Map | HashMap | ConcurrentHashMap |
Set | HashSet / TreeSet | CopyOnWriteArraySet |
Queue | LinkedList | LinkedBlockingQueue |
ConcurrentHashMap
是高并发场景下的优选实现,通过分段锁和无锁读取优化了性能,适合需要频繁读写的应用。
import java.util.concurrent.*;public class ConcurrentCollectionsExample {public static void main(String[] args) throws InterruptedException {// ConcurrentHashMap 示例ConcurrentHashMap<String, Integer> concurrentHashMap = new ConcurrentHashMap<>();concurrentHashMap.put("A", 1);concurrentHashMap.put("B", 2);System.out.println("ConcurrentHashMap: " + concurrentHashMap);// CopyOnWriteArrayList 示例CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();copyOnWriteArrayList.add("X");copyOnWriteArrayList.add("Y");System.out.println("CopyOnWriteArrayList: " + copyOnWriteArrayList);// LinkedBlockingQueue 示例LinkedBlockingQueue<Integer> linkedBlockingQueue = new LinkedBlockingQueue<>();linkedBlockingQueue.put(10);linkedBlockingQueue.put(20);System.out.println("LinkedBlockingQueue: " + linkedBlockingQueue);// 创建一个线程池ExecutorService executorService = Executors.newFixedThreadPool(3);// 使用 ConcurrentHashMap 的示例executorService.submit(() -> {concurrentHashMap.put("C", 3);System.out.println("ConcurrentHashMap (Thread 1): " + concurrentHashMap);});executorService.submit(() -> {concurrentHashMap.get("A");System.out.println("ConcurrentHashMap (Thread 2): " + concurrentHashMap);});// 使用 CopyOnWriteArrayList 的示例executorService.submit(() -> {copyOnWriteArrayList.add("Z");System.out.println("CopyOnWriteArrayList (Thread 3): " + copyOnWriteArrayList);});// 关闭线程池executorService.shutdown();executorService.awaitTermination(1, TimeUnit.MINUTES);// 输出最终结果System.out.println("Final ConcurrentHashMap: " + concurrentHashMap);System.out.println("Final CopyOnWriteArrayList: " + copyOnWriteArrayList);}
}
创建多线程的第四种方式:线程池与 ExecutorService
线程池是一种管理线程的工具,通过复用线程避免频繁创建和销毁的开销,提高资源利用率。ExecutorService
是 Java 提供的线程池接口,支持任务提交、执行管理和结果获取。常见的线程池类型包括固定线程池(newFixedThreadPool
)、单线程池(newSingleThreadExecutor
)和缓存线程池(newCachedThreadPool
)。
以下是一个扩展示例,模拟订单处理并统计完成任务数:
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;public class ThreadPoolDemo {// 用于统计任务完成次数的共享计数器,线程安全private static final AtomicInteger completedTasks = new AtomicInteger(0);// 定义订单处理任务static class OrderTask implements Runnable {private final int orderId;public OrderTask(int orderId) {this.orderId = orderId;}@Overridepublic void run() {try {// 模拟订单处理耗时 1 秒Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " processed order " + orderId);completedTasks.incrementAndGet(); // 任务完成计数加 1} catch (InterruptedException e) {Thread.currentThread().interrupt();}}}// 主方法,演示线程池用法public static void main(String[] args) throws InterruptedException {// 创建固定大小的线程池,最多 3 个线程ExecutorService executor = Executors.newFixedThreadPool(3);// 提交 5 个订单任务for (int i = 1; i <= 5; i++) {executor.submit(new OrderTask(i));}// 关闭线程池,不接受新任务executor.shutdown();// 等待所有任务完成,最多等待 10 秒boolean finished = executor.awaitTermination(10, TimeUnit.SECONDS);if (finished) {System.out.println("All tasks completed. Total: " + completedTasks.get());} else {System.out.println("Timeout! Tasks completed: " + completedTasks.get());}}
}
结果获取方式:
-
使用
Future
:适用于需要同步获取结果的场景。Future<Integer> future = executor.submit(() -> {Thread.sleep(1000);return 42; }); System.out.println("Result: " + future.get());
-
使用
CompletableFuture
:支持异步回调,适合复杂任务流。CompletableFuture.supplyAsync(() -> {try { Thread.sleep(1000); } catch (Exception e) {}return 42; }).thenAccept(result -> System.out.println("Result: " + result));
ThreadLocal
:线程隔离
ThreadLocal
是一个线程局部存储工具,为每个线程提供独立的变量副本,避免线程间的数据干扰。它通过维护一个线程到对象映射表实现隔离,常用于 Web 应用中保存用户会话信息或数据库连接等线程私有数据。需要注意,在使用完毕后调用 remove()
方法清理数据,以防止内存泄漏。
以下是一个扩展示例,模拟 Web 请求中的用户上下文管理:
public class ThreadLocalDemo {// 定义 ThreadLocal,存储每个线程的用户 IDprivate static final ThreadLocal<String> userId = new ThreadLocal<>();// 模拟 Web 请求处理的任务static class RequestTask implements Runnable {private final String id;public RequestTask(String id) {this.id = id;}@Overridepublic void run() {// 设置当前线程的用户 IDuserId.set(id);try {// 模拟处理请求System.out.println(Thread.currentThread().getName() + " handling user: " + userId.get());Thread.sleep(1000); // 模拟耗时操作} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {// 清理 ThreadLocal,避免内存泄漏userId.remove();}}}// 主方法,演示 ThreadLocal 用法public static void main(String[] args) throws InterruptedException {// 创建线程池,模拟多个请求ExecutorService executor = Executors.newFixedThreadPool(2);// 提交两个用户请求executor.submit(new RequestTask("User1"));executor.submit(new RequestTask("User2"));// 关闭线程池并等待executor.shutdown();executor.awaitTermination(5, TimeUnit.SECONDS);}
}
虚拟线程(Project Loom)
虚拟线程是 Java 19 引入的实验性特性(Project Loom),旨在解决传统线程在高并发场景下的资源开销问题。传统线程(平台线程)直接映射到操作系统线程,创建和维护成本高,难以支持大规模并发。而虚拟线程由 JVM 管理,作为轻量级执行单元,依托少量的载体线程运行,适合 IO 密集型任务,例如处理大量网络请求。使用虚拟线程需要启用 --enable-preview
编译和运行参数。
以下是一个扩展示例,模拟高并发请求处理:
import java.util.concurrent.*;public class VirtualThreadDemo {// 定义任务,模拟处理请求static class RequestTask implements Runnable {private final int requestId;public RequestTask(int requestId) {this.requestId = requestId;}@Overridepublic void run() {try {// 模拟 IO 操作(如网络请求)Thread.sleep(1000);System.out.println(Thread.currentThread() + " processed request " + requestId);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}}// 主方法,演示虚拟线程public static void main(String[] args) throws InterruptedException {// 使用虚拟线程执行器,每个任务一个虚拟线程try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {// 提交 100 个请求任务for (int i = 1; i <= 100; i++) {executor.submit(new RequestTask(i));}// 等待 2 秒观察结果Thread.sleep(2000);} // try-with-resources 自动关闭执行器System.out.println("All tasks submitted");}
}
总结
- 初级阶段:学习
Runnable
和synchronized
,掌握线程创建和基本同步。 - 中级阶段:深入理解锁机制、线程池和并发集合,探索
CompletableFuture
的异步编程。 - 进阶方向:关注虚拟线程技术,适应高并发场景的需求。
相关文章:
Java 多线程编程:提升系统并发处理能力!
多线程是 Java 中实现并发任务执行的关键技术,能够显著提升程序在多核处理器上的性能以及处理多任务的能力。本文面向初级到中级开发者,从多线程的基本定义开始,逐步讲解线程创建、状态管理、同步机制、并发工具以及新兴的虚拟线程技术。每部…...
Mininet 的详细设计逻辑
Mininet 是一个轻量级网络仿真工具,其核心目标是在单台物理机上快速构建复杂的虚拟网络拓扑,支持 SDN(软件定义网络)和传统网络协议的实验与验证。其设计逻辑围绕 虚拟化、模块化 和 灵活性 展开,以下是其详细设计架构…...
原生微信小程序实现导航漫游(Tour)
效果: 小程序实现导航漫游 1、组件 miniprogram/components/tour/index.wxml <!--wxml--> <view class"guide" wx:if"{{showGuide}}"><view style"{{guideStyle}}" class"guide-box"><view class&quo…...
Spring(6)——Spring、Spring Boot 与 Spring MVC 的关系与区别
Spring、Spring Boot 与 Spring MVC 的关系与区别 1. 核心定位 Spring 定位:基础框架,提供 IoC(控制反转) 和 DI(依赖注入) 核心功能,管理对象生命周期及依赖关系。功能:支持事务管…...
神聖的綫性代數速成例題2. 行列式的性質
性質 1:行列式與它的轉置行列式相等: 設為行列式,為其轉置行列式,則。 性質 2:交換行列式的兩行 (列),行列式變號: 若行列式經過交換第行和第行得到行列式,則。 性質 3ÿ…...
ModelScope推理QwQ32B
文章目录 ModelScope推理QwQ32Bmodel_scope下载QwQ32BModelScope 调用QwQ-32B ModelScope推理QwQ32B 以下载 qwq32b 为例子 需要安装的 python 包 transformers4.49.0 accelerate>0.26.0 torch2.4.1 triton3.0.0 safetensors0.4.5可以使用 conda 创建一个虚拟环境安装 cond…...
使用unsloth进行grpo强化学习训练
说明 unsloth框架可以进行各种sft训练,包括lora和grpo训练。我参考官方方法,使用模型Qwen2.5-3B-Instruct和数据集gsm8k,写了一个grpo训练的例子。 代码 这个代码加载模型Qwen2.5-3B-Instruct和数据集gsm8k。训练完成后先保存lora模型然后…...
【c++】【智能指针】shared_ptr底层实现
【c】【智能指针】shared_ptr底层实现 智能指针之前已经写过了,但是考虑到不够深入,应该再分篇写写。 1 shared_ptr 1.1 shared_ptr 是什么 std::shared_ptr是一个类模板,它的对象行为像指针,但是它还能记录有多少个对象共享它…...
python拉取大视频导入deepseek大模型解决方案
使用Python拉取大视频并导入大模型,需要综合考虑数据获取、存储、处理和资源管理,确保高效稳定地处理大视频数据,同时充分利用大模型的性能,以下是分步方案及代码示例: --- 1. 分块下载大视频(避免内存溢出…...
【Python】面向对象
编程的两大特点 面向过程:着重于做什么面向对象( oop):着重于谁去做 python是面向对象语言,面向对象三大特点:封装、继承、多态 面向对象:便于代码管理,方便迭代更新。 新式类、经…...
leetcode日记(100)填充每个节点的下一个右侧节点指针
和层序遍历差不多的思路,将节点储存在队列里,一边取出节点一边放入取出节点的左右节点,直到队列空。 /* // Definition for a Node. class Node { public:int val;Node* left;Node* right;Node* next;Node() : val(0), left(NULL), right(NU…...
docker入门篇
使用docker可以很快部署相同的环境,这也是最快的环境构建,接下来就主要对docker中的基础内容进行讲解.Docker 是一个用于开发、交付和运行应用程序的开源平台,它可以让开发者将应用程序及其依赖打包到一个容器中,然后在任何环境中运行这个容器࿰…...
python语法
1. 前面先写import导入模块,完整的语法是: [from 模块名] import [模块 | 类 | 变量 | 函数 | *] [as 别名] 语法还可以是: from 模块名 import 功能名 如果import整个模块的话,需要用.功能名(),来用这个功能ÿ…...
Dify使用部署与应用实践
最近在研究AI Agent,发现大家都在用Dify,但Dify部署起来总是面临各种问题,而且我在部署和应用测试过程中也都遇到了,因此记录如下,供大家参考。Dify总体来说比较灵活,扩展性比较强,适合基于它做…...
微信小程序接入DeepSeek模型(火山方舟),并在视图中流式输出
引言: DeepSeek,作为一款先进的自然语言处理模型,以其强大的文本理解和生成能力著称。它能够处理复杂的文本信息,进行深度推理,并快速给出准确的回应。DeepSeek模型支持流式处理,这意味着它可以边计算边输…...
前端性能优化指标及优化方案
前端性能优化的核心目标是 提高页面加载速度、降低交互延迟、减少资源占用。常见的 Web 性能指标包括 LCP、FID、CLS、TTFB、TTI、FCP 等。 关键性能指标(Web Vitals) 指标优化方案 (1)LCP(Largest Contentful Paint&…...
正则化介绍
简单介绍 正则化是用于控制模型的复杂度,防止模型在训练数据上过度拟合(overfitting)。正则化通过在模型的损失函数中引入额外的惩罚项,来对模型的参数进行约束,从而降低模型的复杂度。这个额外的惩罚通常与模型参数的…...
AI时代:数字媒体的无限可能
人工智能和数字媒体技术正深刻改变着我们的生活。通过大数据分析、机器学习等技术,人工智能不仅能精准预测用户需求,还能在医疗、金融等多个领域提供高效解决方案。与此同时,数字媒体技术的进步使得信息传播更加迅速和广泛。社会计算作为新兴…...
自动化爬虫drissionpage
自动化爬虫drissionpage官网 自动化测试框架:DrissionPage DrissionPage调用工具汇总 网络爬虫工具比较-DrissionPage、Selenium、Playwright...
禁毒知识竞赛主持稿串词
尊敬的各位领导、各位来宾、参赛选手们:大家好! 在市禁毒委员会的领导下,今年我市开展了以“参与禁毒战争,构建和谐社会”为主题的禁毒宣传月活动。为了进一步加强我市禁毒宣传力度,促进社会治安的好转和社会主义物质文…...
【JDK17】Jlink一秒生成精简的JRE
之前介绍了 Java17模块化的JDK,模块化后按需使用Jlink 用于精简生成 JRE 环境,这让快速的开发环境增强了编码的愉悦感。在实际生产环境中使用 mave 进行项目的构建,其次再是精简 JRE 缩小容器镜像体积,为实现一体化的流程…...
机器学习周报--文献阅读
文章目录 摘要Abstract 1 文章内容1.1 模型结构1.1.1 LSTMAT的结构设置1.1.2 AWPSO算法优化模型 1.2 实验与结果讨论1.2.1 处理缺失数据1.2.2 模型评估指标1.2.3 比较实验1.2.4 消融实验(ABLATION EXPERIMENTS) 2相关知识2.1 自适应权重粒子群优化&#…...
硬件地址反序?用位操作为LED灯序“纠偏”。反转二进制数即可解决
特别有意思,LED的灯序与其硬件地址刚好相反,没办法直接通过加1实现二进制进位的亮灯操作,查了一些资料说用数组和switch实现,觉得太麻烦了,思索良久,就想到了反转二进制数解决这个问题。 reverse_bits( )是…...
A* floyd算法 bellman-ford
求源点到目标点最短距离 排序的里面要加上与目标点一个预估距离,与dj算法差距只有这儿 预估要小于等于真实的最短距离,吸引力要适当 越接近实际距离越快 #include<bits/stdc.h> using namespace std;// 方向向量:上、右、下、左 const vector<int> …...
【数据挖掘】KL散度(Kullback-Leibler Divergence, KLD)
KL散度(Kullback-Leibler Divergence, KLD) 是衡量两个概率分布 P 和 Q之间差异的一种非对称度量。它用于描述当使用分布 Q 逼近真实分布 P 时,信息丢失的程度。 KL散度的数学定义 给定两个离散概率分布 P(x)和 Q(x),它们在相同的…...
Linux shell 进度条
概述 在 Linux Shell 中实现一个简单的进度条可以通过 printf 命令结合特殊字符来实现,以下是一个示例脚本,它模拟了一个从 0% 到 100% 的进度条。 作用 反馈任务进度:让用户直观了解任务执行的进展情况,比如文件拷贝、系统更新…...
ctfshow web刷题记录
RCE 第一题 eval代码执行 : 1、使用system 加通配符过滤 ?csystem("tac%20fl*") ; 2、反字节执行 xxx %20 echo 反字节 3、变量转移 重新定义一个变量 让他代替我们执行 4、伪协议玩法 ?cinclude$_GET[1]?>&1php://filter/readc…...
leetcode日记(101)填充每个节点的下一个右侧节点指针Ⅱ
意料之中有这题,将之前的思路换一下即可,层序遍历的思路将record(记录下一个循环的次数)手动加减。 /* // Definition for a Node. class Node { public:int val;Node* left;Node* right;Node* next;Node() : val(0), left(NULL)…...
大语言模型微调和大语言模型应用的区别?
1. 基本概念 微调(Fine-tuning) 定义:微调是指在预训练大语言模型的基础上,通过在特定领域或任务的数据上进一步训练,从而使模型在该特定任务上表现更优。 目的:适应具体的任务需求,比如法律文…...
Leetcode-131.Palindrome Partitioning [C++][Java]
目录 一、题目描述 二、解题思路 【C】 【Java】 Leetcode-131.Palindrome Partitioninghttps://leetcode.com/problems/palindrome-partitioning/description/131. 分割回文串 - 力扣(LeetCode)131. 分割回文串 - 给你一个字符串 s,请你…...
DeepSeek:开启机器人智能化的革命性突破
引言 在2025年全球机器人产业格局中,中国AI公司深度求索(DeepSeek)凭借开源机器人智能控制系统DeepSeek-R1,正在掀起一场从底层算法到应用生态的技术革命。不同于传统机器人依赖预设程序的局限,DeepSeek通过深度推理能…...
解决load()文件报错zipfile.BadZipFile: File is not a zip file
报错如下图: 有可能是资源没有关闭造成了错误,这个网上已经有很多解决方案了,大家可自行查阅。 如果你在别的地方都没有找到解决问题,那么可能是以下这种情况。 1、描述 我在服务器上的代码load()加载文件时,出现了…...
【Tools】Visual Studio Code安装保姆级教程(2025版)
00. 目录 文章目录 00. 目录01. Visual Studio Code概述02. Visual Studio Code下载03. Visual Studio Code安装04. Visual Studio Code配置05. 附录 01. Visual Studio Code概述 Visual Studio Code(简称 VS Code)是由微软开发的一款免费、开源且跨平台…...
Python库安装报错解决思路以及机器学习环境配置详细方案
文章目录 概要第三方库gdalmahotasgraphviznltk-datalazypredictscikit-surprisenb_extensions 机器学习GPU-torch安装torch_geometric安装ubuntu安装显卡驱动dlib安装torch-cluster、torch-scatter、torch-sparse和torch-geometricYOLOapextensorflow-gpu Python && P…...
ETIMEDOUT 网络超时问题
根据日志显示,你遇到的 **ETIMEDOUT 网络超时问题** 是由于 npm 无法连接到企业内部的 Nexus 仓库(http://192.168.55.12:8001)导致的。以下是具体原因和解决方案: 一、问题根源 Nexus 仓库不可达 日志中所有依赖包均尝试从 h…...
superset部署记录
具备网络条件的,完全可以一键部署,不需要折腾。网络条件不具备时,部署记录留存备查。 1、正常模式 详细介绍参考:【开源项目推荐】Apache Superset——最优秀的开源数据可视化与数据探索平台-腾讯云开发者社区-腾讯云 (tencent.c…...
todolist docker 小工具
参考链接 前排提示 没有中文,可使用浏览器 翻译 前提 安装docker安装docker-compose 下载仓库 git clone https://github.com/JordanKnott/taskcafe进行安装 cd taskcafe docker-compose -p taskcafe up -d服务启动后会监听在 3333 端口上,通过浏览器…...
PowerToys:解锁Windows生产力的终极武器
欢迎来到涛涛聊AI。今天想着把win键和加号的组合键映射为win键和Q键盘。经过搜索发现PowerToys。 在数字化办公的浪潮中,效率是职场人永恒的追求。微软推出的 PowerToys 作为Windows官方系统强化工具,凭借其强大的功能和开源免费的特性,已成为…...
内存管理:
我们今天来学习一下内存管理: 1. 内存分布: 我们先来看一下我们下面的图片: 这个就是我们的内存,我们的内存分为栈区,堆区,静态区,常量区; 我们的函数栈帧开辟消耗的内存就是我们…...
ElementUI 表格中插入图片缩略图,鼠标悬停显示大图
如何在 ElementUI 的表格组件 Table 中插入图片缩略图,通过鼠标悬停显示大图?介绍以下2种方式: 方法1:直接在模板元素中插入 <template><el-table :data"tableData"><el-table-column label"图片…...
从被动响应到主动预见:智能可观测性技术的变革与实践
思维导图 一、引言 🌃 想象一下,在一个深夜 🌙,你的关键业务系统突然出现故障 🚨。传统情况下,你可能会收到大量不相关的告警 📱💬💬💬,然后花费…...
【Linux】五种 IO 模型与非阻塞 IO
🌈 个人主页:Zfox_ 🔥 系列专栏:Linux 目录 一:🔥 重新理解 IO🦋 为什么说网络问题的本质是 I/O 问题?🎀 从数据流动看网络通信🎀 网络 I/O 的瓶颈 …...
从零开始开发纯血鸿蒙应用之无框截图
从零开始开发纯血鸿蒙应用 〇、前言二、元素定位1、理论依据2、使用指导 三、认识 ComponentSnapshot1、get 方法2、获取 ComponentSnapshot 实例 四、实现组件截图1、掌握图片编码能力2、保存到图库3、实现组件截图 〇、前言 截图,或者说截屏,已经是每…...
【商城实战(36)】UniApp性能飞升秘籍:从渲染到编译的深度优化
【商城实战】专栏重磅来袭!这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建,运用 uniapp、Element Plus、SpringBoot 搭建商城框架,到用户、商品、订单等核心模块开发,再到性能优化、安全加固、多端适配…...
无人自助空间智能管理系统解决方案(深度优化版)
无人自助空间智能管理系统解决方案(深度优化版) 一、行业痛点与系统价值 传统管理依赖人工: 人工管理模式下,易出现人为失误,如计费错误、资源分配不当等。同时,人工操作效率低下,在高峰时段…...
pycharm配置镜像源【pycharm最新版(23.2.5及以上)方法】
经常遇到pycharm中无法安装或者安装慢的问题,纠结了好久,终于找到这个解决办法了。 为什么要配置镜像源: 因为Python的包管理工具pip一般从PyPI(Python Package Index)下载安装包,但是PyPI位于国外&#x…...
探索ima.copilot:个人知识库搭建的AI新利器
在信息爆炸的时代,知识的积累与管理成为了个人发展的关键。面对海量的科研文献、工作资料和各类信息,如何高效地构建属于自己的知识体系,是许多人面临的挑战。ima.copilot这款AI工具的出现,为解决这一难题提供了新的思路。它凭借强…...
向量数据库技术系列五-Weaviate介绍
一、前言 Weaviate 是由德国公司 SeMI Technologies 开发的开源向量搜索引擎数据库。它结合了向量搜索和图数据库技术,旨在为 AI 应用提供高效的数据存储和检索能力。具有以下的特点: 高性能向量搜索 Weaviate 支持高效的向量索引和近似最近邻&#x…...
1.Qt SDK 的下载和安装
1Qt 下载官⽹: http://download.qt.io/archive/qt/ 2版本自行选择 3下载对应版本的.exe文件 4下载包下载完成 5双击.exe文件,默认下一步,要注册一个qt的账户 6记住程序安装的位置,后面要配置环境变量 7勾3个(组件自行…...
光场中的核心概念:Macro Pixel与SAI的深度解析与实例应用
一、概念详解:从硬件到算法的核心要素 Macro Pixel(宏像素) Macro Pixel是光场相机的硬件核心单元,由微透镜阵列覆盖的一组传感器子像素构成。每个微透镜对应一个宏像素,其子像素分别记录通过该微透镜不同区域的光线方…...