锁的艺术:Java 中的锁类型与欢乐杂谈

嗨,大家好,欢迎来到程序猿漠然公众号,我是漠然。

亲爱的代码侠们,今天我们将走进Java的锁世界,探索那些锁定的秘密。在这个过程中,我会尽量让你们在笑声中学习,所以请准备好你的笑脸和耳朵,因为这是一场关于锁的喜剧之旅。

乐观锁:假设世界是美好的

乐观锁适用于更新操作频繁且冲突较少的情况。它通过CAS(Compare And Swap)操作来实现,如果更新成功,则直接进行修改;如果更新失败,则重新尝试。

想象一下,乐观锁就像是一个总是看到世界美好的一面的人。在Java中,这可以通过Atomic类实现,比如AtomicInteger。它会在更新数值时,先假设不会有其他线程来打扰它,然后再去检查一下是不是真的没有人抢它的风头。

csharp 复制代码
import java.util.concurrent.atomic.AtomicInteger;
public class OptimisticLockerDemo {
    private AtomicInteger count = new AtomicInteger(0);
    public void addCount() {
        int current;
        do {
            current = count.get();
            // 假设没有人修改过计数器
        } while (!count.compareAndSet(current, current + 1));
        // 如果有竞争,这里会重试
    }
}

悲观锁:小心翼翼的守门员

悲观锁适用于读写操作频繁且可能发生冲突的情况。它通过独占锁来确保同一时间只有一个线程可以访问资源。

悲观锁,就像是那个总是担心门外的世界充满了危险的人。在Java中,synchronized关键字和ReentrantLock就是这种锁的代表。它们在给你开门之前,会先确认一下是否有人在外面等着闯进来。

csharp 复制代码
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class PessimisticLockerDemo {
    private final Lock lock = new ReentrantLock();
    public void accessResource() {
        lock.lock();
        try {
            // 这里是安全的代码区
        } finally {
            lock.unlock();
        }
    }
}

读写锁:有的放矢的守卫

读写锁(ReadWriteLock)允许多个读线程同时访问资源,但写线程在写入时需要独占访问权。这样,既可以提高读操作的并发性,又可以保证写操作的一致性。

读写锁就像是那个知道如何区分访客的人。在读写锁面前,读取动作是自由的,任何人都可以读,但写入动作则需要得到允许。

csharp 复制代码
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockerDemo {
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    public void readData() {
        readWriteLock.readLock().lock();
        try {
            // 读操作
        } finally {
            readWriteLock.readLock().unlock();
        }
    }
    public void writeData() {
        readWriteLock.writeLock().lock();
        try {
            // 写操作
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }
}

偏向锁:偏心的守候者

偏向锁旨在减少不必要的锁竞争开销。当锁主要被一个线程持有时,启用偏向模式可以提高性能,因为它会避免不必要的锁竞争检测。

偏向锁就像是那个只喜欢某个特定客户的服务员。在偏向锁的管理下,锁会偏爱第一个访问它的线程,就像服务员总是优先服务他最喜欢的顾客一样。

csharp 复制代码
import java.util.concurrent.atomic.AtomicReference;
public class BiasedLockerDemo {
    private final AtomicReference<Thread> owner = new AtomicReference<>();
    public void doWork() {
        Thread currentThread = Thread.currentThread();
        if (owner.get() == null || owner.get() == currentThread) {
            owner.set(currentThread);
            // 偏向锁:当前线程独占锁
        } else {
            // 如果有其他线程竞争,则释放锁并重新竞争
            owner.compareAndSet(currentThread, null);
            owner.set(currentThread);
        }
        // 执行操作
    }
}

轻量级锁:灵活的舞者

轻量级锁适用于竞争不激烈或短暂的锁需求。当没有竞争时,它通过CAS操作避免使用重量级的操作系统互斥量。

轻量级锁就像是那个在舞蹈中轻盈跳跃的舞者。当没有竞争时,它通过CAS操作旋转跳跃,就像是在跳一场只有一个人的华尔兹。

csharp 复制代码
import java.util.concurrent.atomic.AtomicReference;
public class LightweightLockerDemo {
    private final AtomicReference<Thread> owner = new AtomicReference<>();
    public void doWork() {
        Thread currentThread = Thread.currentThread();
        ```java
        if (owner.get() == null) {
            owner.compareAndSet(null, currentThread);
        } else if (owner.get() != currentThread) {
            // 轻量级锁:如果锁被其他线程持有,则尝试通过自旋等待
            while (!owner.compareAndSet(currentThread, currentThread)) {
                // 自旋等待
            }
        }
        // 执行操作
    }
}

自旋锁:不停转的舞者

自旋锁适用于锁被占用时间非常短的情况。线程在等待锁时不会进入等待状态,而是会循环检查锁的状态,这样可以减少线程状态切换的开销

自旋锁就像是那个在等待时也不会闲着的人。当线程尝试获取锁时,它不会直接放弃,而是会围着锁转来转去,就像是在跳一场不停旋转的探戈。

java 复制代码
import java.util.concurrent.locks.LockSupport;
public class SpinningLockerDemo {
    private final AtomicReference<Thread> owner = new AtomicReference<>();
    public void doWork() {
        Thread currentThread = Thread.currentThread();
        while (!owner.compareAndSet(null, currentThread)) {
            // 自旋等待
            LockSupport.parkNanos(1); // 稍作停顿,然后继续自旋
        }
        // 执行操作
        owner.compareAndSet(currentThread, null); // 释放锁
    }
}

分段锁:聪明的物业管理者

分段锁适用于高度并发的场景,通过将数据分成多个段,可以减少锁竞争,提高系统的并发性能。

分段锁就像是那个把大楼分成不同区域,并为每个区域分配一个守门人的物业管理者。这样,每个守门人只负责自己的区域,避免了所有的访客都在大门口挤来挤去。

java 复制代码
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.HashMap;
import java.util.Map;
public class SegmentedLockerDemo {
    private final Map<Integer, Lock> locks = new HashMap<>();
    public void accessResource(int segment) {
        Lock lock = locks.computeIfAbsent(segment, k -> new ReentrantLock());
        lock.lock();
        try {
            // 这里是安全的代码区
        } finally {
            lock.unlock();
        }
    }
}

希望这次关于Java锁的幽默之旅能让你们在笑声中学习到Java中锁的艺术。记住,锁的世界就像是一部复杂的芭蕾舞剧,每个角色都有自己的舞蹈,而我们的任务就是确保每个人都能跳得开心。

今天的分享就到这里,如果觉得对你有帮助,感谢点赞、分享、关注一波,你的认可是我创造的最大动力。

更多内容请关注公众号:程序猿漠然,一个分享有趣后端知识的公众号。

相关推荐
许苑向上2 分钟前
Dubbo集成SpringBoot实现远程服务调用
spring boot·后端·dubbo
郑祎亦1 小时前
Spring Boot 项目 myblog 整理
spring boot·后端·java-ee·maven·mybatis
本当迷ya1 小时前
💖2025年不会Stream流被同事排挤了┭┮﹏┭┮(强烈建议实操)
后端·程序员
陪学1 小时前
百度遭初创企业指控抄袭,维权还是碰瓷?
人工智能·百度·面试·职场和发展·产品运营
计算机毕设指导62 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
paopaokaka_luck2 小时前
[371]基于springboot的高校实习管理系统
java·spring boot·后端
大数据编程之光3 小时前
Flink Standalone集群模式安装部署全攻略
java·大数据·开发语言·面试·flink
捂月3 小时前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
瓜牛_gn4 小时前
依赖注入注解
java·后端·spring
Estar.Lee4 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip