当前位置: 首页 > news >正文

java/python——两个行为(操作)满足原子性的实现

目录

  • JAVA
      • 方法 1:使用 synchronized 同步块
        • 示例代码
      • 方法 2:使用 ReentrantLock锁
        • 示例代码
      • 方法 3:使用 AtomicReference 或其他原子类
        • 示例代码
      • 方法 4:使用数据库事务(如果涉及数据库操作)
        • 示例代码(使用 JDBC)
      • 方法 5:使用本地队列和后台线程
        • 示例代码
      • 总结
      • android开发拓展:使用回调机制(确保发送成功后再添加)
  • Python
      • 1. 使用线程锁(threading.Lock)
        • 示例代码
      • 2. 使用数据库事务
        • 示例代码(使用 SQLAlchemy)
      • 3. 使用 queue.Queue
        • 示例代码
      • 4. 使用 contextlib 和 contextvars
        • 示例代码
        • 输出
      • 5. 使用 asyncio 和 asyncio.Lock
        • 示例:异步任务中的锁
        • 输出
      • 总结

JAVA

在 Java 中,如果需要确保两个行为(操作)满足原子性,即要么两个操作都成功,要么都不执行,可以使用以下几种方法来实现:

方法 1:使用 synchronized 同步块

synchronized 是 Java 中最简单的同步机制之一,可以确保同一时刻只有一个线程可以执行同步块中的代码。通过将两个操作放在同一个 synchronized 块中,可以确保它们的原子性。

示例代码
import com.google.gson.Gson;
import io.socket.client.Socket;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class MessageManager {private List<Message> messageList = new ArrayList<>();private Socket socket;private Gson gson = new Gson();private final Lock lock = new ReentrantLock();public MessageManager(Socket socket) {this.socket = socket;}public void sendMessage(Message message) {lock.lock();try {// 将消息添加到列表末尾messageList.add(message);// 将消息发送到服务器socket.emit("message", gson.toJson(message));} finally {lock.unlock();}}public List<Message> getMessageList() {return messageList;}
}

在这个例子中,两个操作是原子性的。
可以通过同步块来确保操作的原子性。将消息添加到列表和发送消息的操作放在同一个同步块中,确保它们在同一时间只能被一个线程执行。

方法 2:使用 ReentrantLock锁

希望进一步优化性能,可以将消息先添加到一个本地队列中,然后在后台线程中批量处理消息发送和列表更新。这样可以减少锁的使用频率,提高性能。

ReentrantLock 是 Java 提供的一种显式锁机制,比 synchronized 更灵活。它允许更复杂的锁操作,例如尝试锁定(tryLock)、设置超时时间等。

示例代码
import com.google.gson.Gson;
import io.socket.client.Socket;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class MessageManager {private List<Message> messageList = new ArrayList<>();private Socket socket;private Gson gson = new Gson();private final Lock lock = new ReentrantLock();private final BlockingQueue<Message> messageQueue = new LinkedBlockingQueue<>();public MessageManager(Socket socket) {this.socket = socket;// 启动一个后台线程来处理消息队列new Thread(this::processMessageQueue).start();}public void sendMessage(Message message) {// 将消息添加到队列中messageQueue.add(message);}private void processMessageQueue() {while (true) {try {// 从队列中获取消息Message message = messageQueue.take();lock.lock();try {// 将消息添加到列表末尾messageList.add(message);// 将消息发送到服务器socket.emit("message", gson.toJson(message));} finally {lock.unlock();}} catch (InterruptedException e) {Thread.currentThread().interrupt();break;}}}public List<Message> getMessageList() {return messageList;}
}

在这个例子中,lock.lock()lock.unlock() 确保了两个操作的原子性。finally 块确保即使发生异常,锁也会被正确释放。

方法 3:使用 AtomicReference 或其他原子类

如果两个操作可以封装在一个对象中,可以使用 AtomicReference 或其他原子类来实现原子性。这种方法适用于需要对复杂对象进行原子操作的场景。

示例代码
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;public class AtomicOperations {private List<String> messageList = new ArrayList<>();private AtomicReference<String> lastMessage = new AtomicReference<>();public void performAtomicOperations(String message) {// 操作 1:将消息添加到列表messageList.add(message);// 操作 2:更新 lastMessagelastMessage.set(message);// 打印消息System.out.println("Message added: " + message);}public List<String> getMessageList() {return messageList;}public String getLastMessage() {return lastMessage.get();}
}

在这个例子中,AtomicReference 确保了对 lastMessage 的更新是原子性的。

方法 4:使用数据库事务(如果涉及数据库操作)

如果两个操作涉及数据库操作,可以使用数据库事务来确保原子性。通过事务机制,可以确保一组操作要么全部成功提交,要么全部回滚。

示例代码(使用 JDBC)
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class AtomicOperations {private String dbUrl = "jdbc:mysql://localhost:3306/mydatabase";private String dbUser = "root";private String dbPassword = "password";public void performAtomicOperations(String message) {Connection conn = null;try {conn = DriverManager.getConnection(dbUrl, dbUser, dbPassword);conn.setAutoCommit(false); // 禁用自动提交// 操作 1:将消息插入数据库String sql = "INSERT INTO messages (content) VALUES (?)";try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, message);pstmt.executeUpdate();}// 操作 2:更新某个状态sql = "UPDATE status SET last_message = ?";try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, message);pstmt.executeUpdate();}// 提交事务conn.commit();} catch (SQLException e) {if (conn != null) {try {conn.rollback(); // 回滚事务} catch (SQLException ex) {ex.printStackTrace();}}e.printStackTrace();} finally {if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}}
}

在这个例子中,通过 conn.setAutoCommit(false) 禁用了自动提交,然后在两个操作成功后调用 conn.commit() 提交事务。如果发生异常,调用 conn.rollback() 回滚事务。

方法 5:使用本地队列和后台线程

如果两个操作的执行时间较长,可以将它们放入一个本地队列中,然后在后台线程中批量处理。这样可以减少锁的使用频率,提高性能。

示例代码
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.ReentrantLock;public class AtomicOperations {private List<String> messageList = new ArrayList<>();private final ReentrantLock lock = new ReentrantLock();private final BlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();public AtomicOperations() {// 启动一个后台线程来处理消息队列new Thread(this::processMessageQueue).start();}public void sendMessage(String message) {messageQueue.add(message);}private void processMessageQueue() {while (true) {try {// 从队列中获取消息String message = messageQueue.take();lock.lock();try {// 操作 1:将消息添加到列表messageList.add(message);// 操作 2:打印消息System.out.println("Message added: " + message);} finally {lock.unlock();}} catch (InterruptedException e) {Thread.currentThread().interrupt();break;}}}public List<String> getMessageList() {return messageList;}
}

在这个例子中,消息首先被添加到 messageQueue 中,然后在后台线程中批量处理。通过 lock.lock()lock.unlock() 确保了两个操作的原子性。

总结

  • synchronized 同步块:简单易用,适用于简单的同步需求。
  • ReentrantLock:更灵活,适用于复杂的同步需求。
  • 原子类(如 AtomicReference:适用于对单个对象的原子操作。
  • 数据库事务:适用于涉及数据库操作的场景。
  • 本地队列和后台线程:适用于高并发场景,可以提高性能。

android开发拓展:使用回调机制(确保发送成功后再添加)

如果你需要确保消息成功发送到服务器后才将其添加到列表中,可以使用回调机制。socket.emit 方法通常支持回调函数,可以在消息成功发送后执行回调。

以下是一个示例代码:

import com.google.gson.Gson;
import io.socket.client.Socket;import java.util.ArrayList;
import java.util.List;public class MessageManager {private List<Message> messageList = new ArrayList<>();private Socket socket;private Gson gson = new Gson();public MessageManager(Socket socket) {this.socket = socket;}public void sendMessage(Message message) {// 将消息发送到服务器,并在回调中处理成功或失败socket.emit("message", gson.toJson(message), new Ack() {@Overridepublic void call(Object... args) {// 如果发送成功,将消息添加到列表messageList.add(message);}});}public List<Message> getMessageList() {return messageList;}
}

Python

在 Python 中,实现两个行为的原子性可以通过多种方式,具体取决于操作的类型(例如是否涉及 I/O、数据库操作等)。以下是几种常见的方法:

1. 使用线程锁(threading.Lock)

如果两个操作需要在多线程环境中保持原子性,可以使用 threading.Lock 来确保它们在同一时间只能被一个线程执行。

示例代码
import threadingclass AtomicOperations:def __init__(self):self.message_list = []self.lock = threading.Lock()def perform_atomic_operations(self, message):with self.lock:# 操作 1:将消息添加到列表self.message_list.append(message)# 操作 2:打印消息print(f"Message added: {message}")# 示例使用
atomic_ops = AtomicOperations()
atomic_ops.perform_atomic_operations("Hello, World!")

在这个例子中,with self.lock 确保了 self.message_list.append(message)print(f"Message added: {message}") 两个操作是原子性的。

2. 使用数据库事务

如果两个操作涉及数据库操作,可以使用数据库事务来确保原子性。通过事务机制,可以确保一组操作要么全部成功提交,要么全部回滚。

示例代码(使用 SQLAlchemy)
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmakerBase = declarative_base()class Message(Base):__tablename__ = 'messages'id = Column(Integer, primary_key=True)content = Column(String)# 创建数据库引擎和会话
engine = create_engine('sqlite:///example.db')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()def perform_atomic_operations(message):try:# 操作 1:将消息插入数据库new_message = Message(content=message)session.add(new_message)# 操作 2:更新某个状态(示例)session.query(Message).update({Message.content: message}, synchronize_session=False)# 提交事务session.commit()print(f"Message added: {message}")except Exception as e:# 回滚事务session.rollback()print(f"Failed to add message: {e}")# 示例使用
perform_atomic_operations("Hello, World!")

在这个例子中,通过 session.commit() 提交事务,如果发生异常则调用 session.rollback() 回滚事务。

3. 使用 queue.Queue

queue.Queue 是一个线程安全的队列实现,非常适合在多线程环境中按顺序执行任务。它可以帮助你将任务排队,然后在后台线程中逐一处理这些任务,确保操作的顺序性和线程安全性。

如果两个操作需要在多线程环境中按顺序执行,可以使用 queue.Queue 来确保它们的原子性。queue.Queue 是线程安全的,可以用于在多线程之间传递消息。

示例代码
import threading
import queueclass AtomicOperations:def __init__(self):self.message_list = []self.message_queue = queue.Queue()def worker(self):while True:message = self.message_queue.get()if message is None:break# 操作 1:将消息添加到列表self.message_list.append(message)# 操作 2:打印消息print(f"Message added: {message}")self.message_queue.task_done()def perform_atomic_operations(self, message):self.message_queue.put(message)def start_worker(self):threading.Thread(target=self.worker, daemon=True).start()# 示例使用
atomic_ops = AtomicOperations()
atomic_ops.start_worker()
atomic_ops.perform_atomic_operations("Hello, World!")
atomic_ops.message_queue.join()  # 等待队列中的所有任务完成

在这个例子中,message_queue 确保了消息的处理是线程安全的。

4. 使用 contextlib 和 contextvars

contextlibcontextvars 可以用于在异步环境中保持原子性。contextvars 提供了上下文变量,可以在异步任务之间传递状态,而 contextlib 提供了上下文管理器,可以确保操作的原子性。

示例代码
import asyncio
import contextvars
import contextlib# 定义一个上下文变量
message_var = contextvars.ContextVar('message_var')# 定义一个上下文管理器
@contextlib.contextmanager
def atomic_operations():token = message_var.set("Initial value")  # 设置初始值try:yieldfinally:message_var.reset(token)  # 恢复原始值async def process_message(message):with atomic_operations():# 操作 1:设置上下文变量message_var.set(message)# 操作 2:打印消息print(f"Processing message: {message_var.get()}")# 模拟异步操作await asyncio.sleep(1)# 操作 3:再次打印消息print(f"Finished processing message: {message_var.get()}")async def main():await asyncio.gather(process_message("Hello"),process_message("World"))# 运行异步主函数
asyncio.run(main())
输出
Processing message: Hello
Processing message: World
Finished processing message: Hello
Finished processing message: World

5. 使用 asyncio 和 asyncio.Lock

asyncio.Lock 是一个异步锁,用于在异步环境中确保操作的原子性。它可以帮助你确保在多个异步任务中,某些操作不会同时被执行。

示例:异步任务中的锁

假设你有一个异步任务,需要确保某些操作是原子性的。

import asyncioclass MessageProcessor:def __init__(self):self.message_list = []self.lock = asyncio.Lock()async def add_message(self, message):async with self.lock:# 操作 1:将消息添加到列表self.message_list.append(message)# 操作 2:打印消息print(f"Message added: {message}")async def main():processor = MessageProcessor()async def task(message):await processor.add_message(message)await asyncio.gather(task("Hello"),task("World"),task("Python"))print("Final message list:", processor.message_list)# 运行异步主函数
asyncio.run(main())
输出
Message added: Hello
Message added: World
Message added: Python
Final message list: ['Hello', 'World', 'Python']

总结

  • 线程锁(threading.Lock:适用于多线程环境。
  • 数据库事务:适用于涉及数据库操作的场景。
  • 队列(queue.Queue:适用于多线程环境中按顺序执行操作。
  • 上下文管理器(contextlibcontextvars:适用于需要在异步环境中保持原子性的场景。
  • 异步锁(asyncio.Lock:适用于异步环境。

相关文章:

  • Web前端:Overflow属性(超出裁剪属性)
  • vllm+vllm-ascend本地部署QwQ-32B
  • MYSQL之基础认识(卸载安装登录, 基本概念)
  • Linux论坛安装
  • 【第四章】19-匹配规则定义
  • JavaScript实现二级菜单
  • 【uniapp-兼容性处理】安卓uView组件中u-input后置插槽不展示
  • Vmware esxi 给现有磁盘增加空间后并扩展系统里磁盘空间
  • Redis 键管理
  • AI Agent认知框架(ReAct、函数调用、计划与执行、自问自答、批判修正、思维链、思维树详解和对比,最后表格整理总结
  • redis-7 安装
  • linux sysfs使用cat无显示的原因:返回值未赋值
  • 《深入解析C++中的explicit关键字:防止隐式转换的利器》
  • C语言main的参数;argc与argv
  • 开源键鼠共享软件的“爱恨情仇“:Deskflow、InputLeap与Barrier的演化史
  • Shell脚本-四则运算符号
  • spark基础介绍
  • Neowise Labs Contest 1 (Codeforces Round 1018, Div. 1 + Div. 2)(A~E)
  • 在Ubuntu 18.04下编译OpenJDK 11
  • 【每天一个知识点】主题建模(Topic Modeling)
  • 郑州卫健委通报郑飞医院“血液净化”问题:拟撤销该院血液净化技术备案
  • 浙江桐乡征集涉企行政执法问题线索,含乱收费、乱罚款、乱检查等
  • 十大券商看后市|A股下行波动风险有限,震荡中有望逐步抬升
  • 中共中央办公厅、国务院办公厅印发《农村基层干部廉洁履行职责规定》
  • 甘肃古浪县发生3.0级地震,未接到人员伤亡和财产损失报告
  • 寻找“香奈儿”代工厂