墨风如雪博客

  • 源码小店
  • 导航站
  • 登录
  • java
  • 资源分享
让AI使用变得如此简单
  1. 首页
  2. java
  3. 正文

Java中的原子类与JUC包中的锁有何区别?

2023年 7月 12日 94点热度 0人点赞 0条评论

1. 前言

并发编程中,锁是一种用于保护共享资源的机制,Java中的原子类和JUC包中的锁都是用于实现并发控制的工具。本文将介绍Java中的原子类和JUC包中的锁,并对它们之间的区别进行分析。

2. Java中的原子类

2.1 原子类的概述

Java中的原子类是一种线程安全的、不可变的类型,它们提供了一些基本的原子操作,如原子更新、原子加减等,可以在没有锁的情况下保证并发安全。Java中的原子类位于java.util.concurrent.atomic包中,常用的原子类包括AtomicBoolean、AtomicInteger、AtomicLong等。

2.2 原子类的分类

Java中的原子类可以分为以下三类:

  • 原子更新基本类型类:如AtomicBoolean、AtomicInteger、AtomicLong等,它们可以原子性地更新基本类型的值;
  • 原子更新数组类:如AtomicIntegerArray、AtomicLongArray等,它们可以原子性地更新数组中的元素;
  • 原子更新引用类型类:如AtomicReference、AtomicStampedReference等,它们可以原子性地更新引用类型的值。

2.3 原子类的常用方法

Java中的原子类提供了一些常用的方法,如下表所示:

方法名 说明
get() 获取当前值
getAndSet() 获取当前值,并设置为新值
compareAndSet() 比较并设置,如果当前值等于预期值,则原子地设置为新值,并返回true,否则返回false
addAndGet() 原子地将给定值加到当前值,并返回更新后的值
incrementAndGet() 原子地将当前值加1,并返回更新后的值

以下是一个使用AtomicInteger的示例代码:

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerExample {
    private static AtomicInteger counter = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
        Runnable task = () -> {
            for (int i = 0; i < 10000; i++) {
                counter.incrementAndGet();
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Counter value: " + counter.get());
    }
}

上述代码中,使用AtomicInteger实现了一个计数器,两个线程并发地对计数器进行加操作,最终输出计数器的值。

3. JUC包中的锁

3.1 锁的概述

锁是一种用于控制多个线程对共享资源进行访问的机制。在Java中,常用的锁包括synchronized关键字、ReentrantLock、ReadWriteLock等。JUC包中的锁在Java中提供了更为灵活和高效的锁实现。

3.2 JUC包中的重入锁

3.2.1 重入锁的概述

ReentrantLock是JUC包中的一种可重入锁,它与synchronized关键字相比,提供了更为灵活的锁控制方式,支持公平锁和非公平锁,并且可以通过tryLock()方法尝试获取锁而不阻塞线程。

3.2.2 重入锁的实现原理

ReentrantLock的实现原理与synchronized关键字类似,都是基于Java的内置监视器实现的。但是,ReentrantLock相比synchronized关键字,提供了更为灵活和高效的锁控制方式。

3.2.3 重入锁的使用方法

以下是一个使用ReentrantLock的示例代码:

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockExample {
    private static int counter = 0;
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        Runnable task = () -> {
            try {
                lock.lock();
                for (int i = 0; i < 10000; i++) {
                    counter++;
                }
            } finally {
                lock.unlock();
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Counter value: " + counter);
    }
}

上述代码中,使用ReentrantLock实现了一个计数器,两个线程并发地对计数器进行加操作,最终输出计数器的值。

3.3 JUC包中的读写锁

3.3.1 读写锁的概述

ReadWriteLock是JUC包中的一种读写锁,它支持多个线程同时读取共享资源,但只允许一个线程写入共享资源。在读多写少的情况下,使用读写锁可以大大提高系统的并发性能。

3.3.2 读写锁的实现原理

ReadWriteLock的实现原理与ReentrantLock类似,也是基于Java的内置监视器实现的。但是,ReadWriteLock通过维护读锁和写锁两个锁来实现对共享资源的控制。

3.3.3 读写锁的使用方法

以下是一个使用ReadWriteLock的示例代码:

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {
    private static int counter = 0;
    private static ReadWriteLock lock = new ReentrantReadWriteLock();

    public static void main(String[] args) throws InterruptedException {
        Runnable readTask = () -> {
            try {
                lock.readLock().lock();
                System.out.println("Counter value: " + counter);
            } finally {
                lock.readLock().unlock();
            }
        };

        Runnable writeTask = () -> {
            try {
                lock.writeLock().lock();
                counter++;
            } finally {
                lock.writeLock().unlock();
            }
        };

        Thread t1 = new Thread(readTask);
        Thread t2 = new Thread(readTask);
        Thread t3 = new Thread(writeTask);
        Thread t4 = new Thread(writeTask);

        t1.start();
        t2.start();
        t3.start();
        t4.start();

        t1.join();
        t2.join();
        t3.join();
        t4.join();
    }
}

上述代码中,使用ReadWriteLock实现了一个计数器,两个线程并发地读取计数器的值,两个线程并发地增加计数器的值,演示了读写锁的使用方法。

3.4 JUC包中的其他锁

JUC包中还提供了其他锁,如公平锁和非公平锁、可重入读写锁、独占锁和共享锁等。这些锁的使用方法与前面介绍的锁类似,这里不再赘述。

4. Java中的原子类与JUC包中的锁的区别

4.1 适用场景的不同

Java中的原子类适合用于对单个变量进行原子性操作的场景,如计数器、标志位等;而JUC包中的锁适合用于对多个变量或数据结构进行原子性操作的场景,如读写文件、数据库操作等。

4.2 实现方式的不同

Java中的原子类使用了CAS(Compare And Swap)算法,通过硬件支持实现了原子性操作;而JUC包中的锁则是基于Java的内置监视器实现的,使用了传统的互斥锁、共享锁等机制。

4.3 性能的不同

Java中的原子类由于使用了硬件支持的CAS算法,因此在并发量较小的情况下性能较好;而JUC包中的锁由于需要使用传统的锁机制,因此在并发量较大的情况下性能较好。

4.4 粒度的不同

Java中的原子类的粒度较细,只能对单个变量进行原子性操作,而JUC包中的锁的粒度较粗,可以对多个变量或数据结构进行原子性操作。

4.5 使用方式的不同

Java中的原子类使用起来比较简单,只需要调用相应的方法即可;而JUC包中的锁需要手动加锁和解锁,使用起来相对复杂。

5. 总结

本文介绍了Java中的原子类和JUC包中的锁的概念、分类、常用方法、实现原理、适用场景、性能和使用方式等方面的知识。Java中的原子类适用于对单个变量进行原子性操作的场景,而JUC包中的锁适用于对多个变量或数据结构进行原子性操作的场景。两者的实现方式、性能、粒度和使用方式都有所不同,应根据实际需求选择合适的并发控制工具。

6. 扩展点

除了Java中的原子类和JUC包中的锁外,还有其他的并发控制工具,如信号量、倒计时门闩、并行数组等。在实际的并发编程中,应根据实际需求选择合适的并发控制工具,并结合具体的业务场景进行性能优化。

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: java 原子性 原子类 多线程 并发 教程 线程池
最后更新:2023年 6月 11日

墨风如雪

一个热爱生活,热爱分享的程序员

打赏 点赞
< 上一篇
下一篇 >

文章评论

您需要 登录 之后才可以评论

墨风如雪

一个热爱生活,热爱分享的程序员

最新 热点 随机
最新 热点 随机
告别机械感!OpenAudio S1让AI声音活起来 Sora触手可及!微软必应AI视频生成器,全民创作时代来临? 阿里WebAgent开源:引领自主搜索新纪元 重磅炸弹!字节跳动开源BAGEL:70亿参数,统一多模态理解与生成,AI“全能王”诞生记! 小米MiMo-VL:7B参数,怎么就成了多模态界的“越级打怪王”? 炸裂!DeepSeek 8B 量化版降临:告别显存焦虑,你的 3080 Ti 也能玩转顶级大模型了!
AI圈炸锅了!Mistral Medium 3:性能 SOTA,成本打骨折,企业玩家的新宠?字节终于开源“扣子”同款引擎了!FlowGram:AI 时代的可视化工作流利器告别“微信黑箱”!Chatlog:让你的聊天记录也能拥有“AI大脑”!字节跳动 Seed-Coder-8B:不靠人工洗数据,这80亿参数的小模型如何写出顶尖代码?85倍速的视觉革命:苹果发布 FastVLM,让你的 iPhone ‘看图说话’,快到飞起!告别AI视频“变脸怪”!腾讯混元Hunyuan Custom重磅开源,主体一致性“王炸”来了!
一台新到手的VPS服务器必做的配置 SpringBoot扩展点之ApplicationContextInitializer Aero-1-Audio来了:1.5B参数,性能直逼SOTA,告别长音频分割烦恼 谷歌下场,寸草不生?Firebase Studio 挥舞 AI 大棒,誓要统一开发者江湖! Gemini 2.5:AI界的“记忆之王”是如何炼成的? 深入解析Redis支持的数据结构
标签聚合
算法 AI java deepseek spring 教程 设计模式 动态规划

COPYRIGHT © 2023 墨风如雪博客. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

免责声明 - 隐私政策