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

Java后端中的并发控制:从锁机制到无锁编程的实现

Java后端中的并发控制:从锁机制到无锁编程的实现

大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们来探讨Java后端开发中非常重要的一部分内容——并发控制。在多线程环境下,如何保证数据一致性和程序的正确性是我们面临的主要挑战。本文将通过对锁机制的深入介绍,并引入无锁编程的实现方式,帮助大家掌握并发编程中的核心技术。

一、Java中的锁机制

在Java中,锁(Lock)是控制多线程并发的重要工具,它用于确保共享资源在同一时间只能被一个线程访问。最基础的同步机制是synchronized关键字,它为方法或代码块提供了一种隐式锁。

1. synchronized的使用

synchronized关键字可以修饰方法或代码块,用于保证某个线程在执行代码块时,其他线程不能进入相同的代码块。

示例代码:

package cn.juwatech.concurrent;public class SynchronizedExample {private int count = 0;public synchronized void increment() {count++;}public int getCount() {return count;}public static void main(String[] args) {SynchronizedExample example = new SynchronizedExample();Thread thread1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final count: " + example.getCount());}
}

在这段代码中,increment()方法通过synchronized关键字保证了线程安全。然而,synchronized的粒度较粗,会阻塞其他线程进入同步代码块,因此在并发量较高时可能会影响性能。

2. ReentrantLock的使用

ReentrantLockjava.util.concurrent.locks包中的锁,它提供了更灵活的锁机制,比如可中断锁等待、非阻塞锁获取等。

示例代码:

package cn.juwatech.concurrent;import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockExample {private final ReentrantLock lock = new ReentrantLock();private int count = 0;public void increment() {lock.lock();try {count++;} finally {lock.unlock();}}public int getCount() {return count;}public static void main(String[] args) {ReentrantLockExample example = new ReentrantLockExample();Thread thread1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final count: " + example.getCount());}
}

这里使用了ReentrantLock来代替synchronized,我们显式调用lock()unlock()来控制锁的获取与释放。相比synchronizedReentrantLock允许更灵活的锁操作,例如支持公平锁和非公平锁的选择。

二、无锁编程的实现

虽然锁机制能保证线程安全,但在高并发环境下,锁的竞争可能导致性能瓶颈。为了进一步提升并发性能,可以考虑使用无锁编程。Java的java.util.concurrent.atomic包提供了许多原子操作类,例如AtomicIntegerAtomicReference等,它们通过硬件层面的CAS(Compare And Swap)操作来实现线程安全,而无需使用锁。

1. 使用AtomicInteger实现无锁递增

通过AtomicInteger,我们可以避免使用锁来实现线程安全的递增操作。

示例代码:

package cn.juwatech.concurrent;import java.util.concurrent.atomic.AtomicInteger;public class AtomicIntegerExample {private AtomicInteger count = new AtomicInteger(0);public void increment() {count.incrementAndGet();}public int getCount() {return count.get();}public static void main(String[] args) {AtomicIntegerExample example = new AtomicIntegerExample();Thread thread1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {example.increment();}});thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final count: " + example.getCount());}
}

通过AtomicInteger,可以避免锁的使用,同时保证并发操作的原子性。这种无锁编程方式适用于对性能要求较高的场景,特别是轻量级的操作。

2. 使用AtomicReference实现无锁对象更新

除了基本的数值类型,AtomicReference可以帮助我们实现对对象的无锁更新。

示例代码:

package cn.juwatech.concurrent;import java.util.concurrent.atomic.AtomicReference;public class AtomicReferenceExample {private static class Account {private String name;private int balance;public Account(String name, int balance) {this.name = name;this.balance = balance;}public String getName() {return name;}public int getBalance() {return balance;}public void setBalance(int balance) {this.balance = balance;}}private AtomicReference<Account> account = new AtomicReference<>(new Account("Alice", 1000));public void updateBalance(int newBalance) {Account currentAccount;Account newAccount;do {currentAccount = account.get();newAccount = new Account(currentAccount.getName(), newBalance);} while (!account.compareAndSet(currentAccount, newAccount));}public Account getAccount() {return account.get();}public static void main(String[] args) {AtomicReferenceExample example = new AtomicReferenceExample();Thread thread1 = new Thread(() -> {example.updateBalance(1200);});Thread thread2 = new Thread(() -> {example.updateBalance(1500);});thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final balance: " + example.getAccount().getBalance());}
}

这里我们通过AtomicReference实现了账户余额的无锁更新。compareAndSet()方法会在内部循环,直到成功更新对象,这种方式避免了锁的开销。

三、StampedLock和ReadWriteLock

在读多写少的场景中,传统的排它锁可能会造成大量线程的等待,因此Java提供了读写锁机制来优化这类场景。ReadWriteLock允许多个线程同时读取数据,而写操作则会独占锁。

1. ReadWriteLock示例

package cn.juwatech.concurrent;import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadWriteLockExample {private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();private int value = 0;public int readValue() {rwLock.readLock().lock();try {return value;} finally {rwLock.readLock().unlock();}}public void writeValue(int newValue) {rwLock.writeLock().lock();try {value = newValue;} finally {rwLock.writeLock().unlock();}}public static void main(String[] args) {ReadWriteLockExample example = new ReadWriteLockExample();Thread writer = new Thread(() -> {example.writeValue(100);});Thread reader = new Thread(() -> {System.out.println("Read value: " + example.readValue());});writer.start();reader.start();try {writer.join();reader.join();} catch (InterruptedException e) {e.printStackTrace();}}
}

这里通过ReentrantReadWriteLock来分别控制读写操作。多个线程可以同时读取数据,但写操作会阻塞读线程,确保数据的一致性。

总结

本文通过对锁机制(包括ReentrantLocksynchronized、读写锁)

和无锁编程(AtomicIntegerAtomicReference)的介绍,详细分析了在Java后端开发中如何进行并发控制。针对不同的应用场景,我们可以选择适合的并发控制方案,从而提高程序的并发性能和稳定性。

本文著作权归聚娃科技微赚淘客系统开发者团队,转载请注明出处!

http://www.lryc.cn/news/575434.html

相关文章:

  • 供应链管理:主要生产计划类型及其相关信息
  • Vue-14-前端框架Vue之应用基础嵌套路由和路由传参
  • 【fish-speech】新模型openaudio-s1-mini尝鲜
  • 【windows处理技巧】如何缩小PDF
  • R语言机器学习算法实战系列(二十六)基于tidymodels的XGBoost二分类器全流程实战
  • 【力扣 困难 C】32. 最长有效括号
  • 数据结构进阶 - 第三章 栈与队列
  • ubuntu 下cursor的安装
  • 深入了解 AWS EventBridge
  • 多相机人脸扫描设备如何助力高效打造数字教育孪生体?
  • Java设计模式->责任链模式的介绍
  • 书籍在行列都排好序的矩阵中找数(8)0626
  • 【音视频】Ubuntu下配置ffmpeg库
  • Maven Javadoc 插件使用详解
  • 【WebSocket】学习总结
  • Python 数据分析与可视化 Day 8 - Pandas 高级操作技巧
  • MFC制作动态波形图( ChartCtrl)
  • Python(一)实现一个爬取微信小程序数据的爬虫+工程化初步实践
  • 【FR801xH】Ubuntu24.04搭建富芮坤FR801xH系列开发环境教程
  • 美团京东Clean Architecture实战
  • 【算法深练】栈特性的解题密码:LIFO规则在题型中的灵活运用
  • 生僻字处理工具类
  • 价格敏感带争夺战!澳洲电商双雄增长密码,3大本土护城河尚存
  • C# 项目使用obfuscar混淆
  • 华曦达港股IPO递表,AI Home生态构建智能生活新蓝图
  • 2025 Java开发生态全景图:云原生、AI与性能优化的技术融合
  • 广州华锐互动:技术与创意双驱动的 VR 先锋​
  • 基于组件的软件开发(CBSD)与面向服务的架构(SOA)的对比分析
  • Android-Layout Inspector使用手册
  • VSCode插件开发