详解Java中的悲观锁与乐观锁

详解Java中的悲观锁与乐观锁

什么是锁?

在多线程编程中,为了保证线程安全和数据一致性,我们常常采用锁机制。锁顾名思义就是在一段代码区域加上一个锁,使得同一时刻只有一个线程可以访问该代码区域。Java中的锁机制主要有两种:悲观锁和乐观锁。

悲观锁

悲观锁的思想就是认为并发情况下不同线程之间会发生冲突,因此在整个处理过程中,都加上了同步锁,让线程独占资源,其他线程等待。

Java中常见的悲观锁实现方式是synchronized关键字,例如:

public synchronized void method(){
    // 该方法的代码块
}

synchronized关键字会自动加锁,当线程执行synchronized代码块时,其他线程无法访问该代码块,只能等待。

乐观锁

乐观锁的思想则是相反的,它认为并发情况下不同线程之间不会发生冲突,因此不需要加锁。在更新数据时,判断该数据有没有被其他线程修改,若该数据被修改,则暂停该次操作,重新读取数据并重试。

Java中的乐观锁实现方式一般是通过CAS(Compare And Swap)来实现,例如:

public class Counter {
    private AtomicInteger num = new AtomicInteger(0);

    public void increment() {
        int newVal;
        do {
            newVal = num.get() + 1;
        } while(!num.compareAndSet(num.get(), newVal));
    }
}

CAS先获取内存中的值,然后基于获取的值来计算新值,最后通过CAS操作来尝试更新内存中的值。如果这个值不是期望的,那么修改失败,就需要重试。

悲观锁与乐观锁的选择

在选择使用悲观锁还是乐观锁时,需要根据实际情况来进行考虑。

悲观锁适合于写操作比较多的情况,因为写操作需要独占资源。悲观锁在实现简单的同时也存在着性能问题,因为当访问量大时,悲观锁会降低系统的吞吐量。

乐观锁适合于读操作比较多的情况,因为读操作不需要独占资源,多个线程可以共同读取一个数据。并且乐观锁的实现方式可以避免了加锁引起的性能问题。

示例

下面两个示例演示了悲观锁和乐观锁的实现方式。其中线程安全的计数器Counter类用于演示两种锁的实现方式。

悲观锁示例

public class PessimisticLockExample {
    private static int value = 0;

    public static synchronized void increment() {
        value++;
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    increment();
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    increment();
                }
            }
        });

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

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

乐观锁示例

public class OptimisticLockExample {
    private static AtomicInteger value = new AtomicInteger(0);

    public static void increment() {
        int oldValue;
        int newValue;
        do {
            oldValue = value.get();
            newValue = oldValue + 1;
        } while(!value.compareAndSet(oldValue, newValue));
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    increment();
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    increment();
                }
            }
        });

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

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

总结

悲观锁的实现方式简单直接,但存在性能问题,适合于写操作比较多的情况。乐观锁的实现方式可以避免加锁带来的性能问题,适合于读操作比较多的情况。在实际情况中,需要根据具体情况选择合适的锁实现方式来保证线程安全和数据一致性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Java中的悲观锁与乐观锁 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Midjourney:一步一步教你如何使用 AI 绘画 MJ

    一步一步如何使用 Midjourney 教程:教学怎么用 MJ? 一、Midjourney(MJ)是什么? Midjourney是一款使用文字描述来生成高质量图像的AI绘画工具。这篇文章主要介绍了Midjourney及其用途,并针对Midjourney的使用提供了一些指南。该工具可以帮助人们更快速、更容易地创建图像。 与市场上的其他AI绘画工具相比,Midj…

    Java 2023年4月22日
    00
  • 使用spring框架中的组件发送邮件功能说明

    使用Spring框架中的组件发送邮件功能说明 Spring框架提供了非常方便的邮件发送组件,通过简单的配置就可以实现邮件发送的功能,本文将详细讲解如何使用Spring框架中的组件发送邮件。 步骤1:添加依赖 在pom.xml文件中添加以下依赖: <dependency> <groupId>org.springframework<…

    Java 2023年5月19日
    00
  • 详解Struts2拦截器机制

    详解Struts2拦截器机制 1. 什么是Struts2拦截器 Struts2拦截器是一个非常重要的组件,用于对请求进行拦截和处理,同时也是整个Struts2框架的核心。 在Struts2中,每个请求都会经过多个拦截器的处理,每个拦截器只是完成了部分工作,多个拦截器组合在一起,最终完成了一个完整的请求处理流程。 2. Struts2拦截器机制的流程 Stru…

    Java 2023年5月20日
    00
  • java中的Io(input与output)操作总结(二)

    下面我来详细讲解 “java中的Io(input与output)操作总结(二)” 的完整攻略。 Io简介 在 Java 中,Io 就是输入和输出操作。常用的 Io 操作包含文件流、输入流、输出流等。在本攻略中,我们主要关注文件流、输入流、输出流的使用。 文件流 文件流用于操作文件,常用的文件流有文件输入流 FileInputStream 和文件输出流 Fil…

    Java 2023年5月26日
    00
  • java异常处理机制示例(java抛出异常、捕获、断言)

    Java 异常处理机制是 Java 编程语言的一部分,可以用来处理可能在程序执行期间发生的错误或特殊情况。该机制利用两个机制来实现异常处理:抛出异常和捕获异常。在代码块中,如果发生了异常,它将会被抛出,然后在某个程序块中被捕获并处理。下面我们将通过两条示例详细讲解 Java 异常处理机制和代码实现。 1. 抛出异常 Java 中的异常通常是以 throw 语…

    Java 2023年5月27日
    00
  • struts1登录示例代码_动力节点Java学院整理

    Struts1登录示例代码攻略 简介 Struts1 是一个 Web 应用程序的 MVC 框架,通过使用 Struts1 框架,可以更加方便地管理 Web 应用程序中的各个模块,提高代码的重用性和可维护性。本文将介绍使用 Struts1 实现登录功能的示例代码。 实现步骤 本示例的实现步骤如下: 创建登录页面 login.jsp 创建 Struts1 配置文…

    Java 2023年5月20日
    00
  • SpringBoot集合Mybatis过程解析

    SpringBoot集成Mybatis过程解析 1. 简介 SpringBoot是基于Spring框架的快速应用开发框架,整合了众多好用的组件,非常适合开发中小型项目。而Mybatis则是一个轻量级的ORM框架,可以让我们更加方便地操作数据库。 在本篇攻略中,我们将会详细讲解如何在SpringBoot项目中集成Mybatis,并完成对数据库的CRUD操作。 …

    Java 2023年5月19日
    00
  • 基于IDEA创建SpringMVC项目流程图解

    下面是基于IDEA创建SpringMVC项目的完整攻略流程图解: 前置条件 安装JDK和IDEA 熟悉Java和SpringMVC开发 创建SpringMVC项目 启动IDEA,点击“Create New Project”来创建新项目 选择“Spring Initializr”来创建SpringMVC项目 在“New Project”窗口中,选择“Sprin…

    Java 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部