Java多线程之显示锁和内置锁总结详解

yizhihongxing

Java多线程之显示锁和内置锁总结详解

前言

随着现代计算机的发展,CPU的速度和核心数量逐渐增加,让多线程编程变得越来越重要。Java作为一门支持多线程的语言,在多线程编程方面也提供了一系列的API和机制。本文将重点介绍Java中的两种锁:显示锁和内置锁,并对它们进行详细分析和对比。

什么是锁?

在多线程编程中,为了保证共享资源的正确访问,我们经常需要对这些共享资源进行加锁操作,这时就需要使用锁机制。锁机制主要用于三个目的:

  1. 互斥:同一时刻只允许一个线程访问锁保护的资源;
  2. 可见性:一个线程修改了锁保护的共享变量,其他线程可以看到这个修改;
  3. 有序性:锁的获取和释放具有一定的顺序性,以保证程序正确性。

显示锁

显示锁是Java提供的一种手动管理锁的机制,最主要的类是 java.util.concurrent.locks.Lock。Lock接口定义了两个基本方法,分别是 lock()unlock()。在代码块中使用Lock锁进行同步时,需要手动获取锁和释放锁,代码示例:

Lock lock = new ReentrantLock();
...
lock.lock();
try {
    // 执行需要同步的操作
} catch (Exception e) {
    // 异常处理
} finally {
    lock.unlock();
}

显示锁相比于内置锁更加灵活,它支持条件变量,可以响应中断请求,同时也支持读写锁,可以控制读写操作的并发访问等。

内置锁

内置锁是Java的默认锁机制,也称为 synchronized 同步块,它是Java中最简单和最常见的同步机制之一。内置锁的锁对象是调用该同步块的对象,同一时刻只有一个线程能够获取锁,其他线程需要等待该锁的释放才能继续执行。示例代码:

synchronized (obj) {
    // 执行需要同步的操作
}

内置锁的优点是使用方便,不需要手动获取和释放锁,自动管理。缺点是功能相对简单,只能支持最基本的互斥性。

总结

  1. 显示锁是Java提供的一种手动管理锁的机制,Lock接口定义了两个基本方法;
  2. 内置锁是Java默认的锁机制,也称为synchronized同步块;
  3. 显示锁比内置锁更加灵活,支持条件变量,可以响应中断请求,同时也支持读写锁;
  4. 内置锁使用方便,不需要手动获取和释放锁,自动管理。但功能相对简单,只能支持最基本的互斥性。

示例

示例一:使用显示锁实现多线程同步

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SyncTest {

    private int count = 0;
    private Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public void decrement() {
        lock.lock();
        try {
            count--;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SyncTest syncTest = new SyncTest();

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                syncTest.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                syncTest.decrement();
            }
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println(syncTest.count);
    }
}

该示例使用显示锁来保证 count 总是在多线程环境下正确,Lock.lock()方法获取锁,try...finally 语句中的 unlock() 方法释放锁。运行该程序会产生 0 的输出,证明了程序的正确性。

示例二:使用内置锁实现多线程同步

public class SyncTest {

    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized void decrement() {
        count--;
    }

    public static void main(String[] args) throws InterruptedException {
        SyncTest syncTest = new SyncTest();

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                syncTest.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                syncTest.decrement();
            }
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println(syncTest.count);
    }
}

该示例使用内置锁来保证 count 总是在多线程环境下正确,使用 synchronized 对方法进行同步。运行该程序会产生 0 的输出,证明了程序的正确性。

结语

本文对Java中的显示锁和内置锁进行了详细的介绍和比较,并给出了代码示例。在多线程编程中,锁机制是保证程序正确性的重要手段,使用锁机制时需要根据实际情况进行选择。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程之显示锁和内置锁总结详解 - Python技术站

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

相关文章

  • Springboot使用influxDB时序数据库的实现

    接下来我将详细讲解“Springboot使用influxDB时序数据库的实现”的完整攻略。首先需要明确的是,influxDB是一个高性能的时序数据库,专门用于处理时间序列数据。而Springboot是一个基于Spring框架的应用程序快速开发框架。 引入influxDB依赖 在Springboot项目的pom.xml文件中,添加以下依赖: <depen…

    Java 2023年5月20日
    00
  • Java对象转json JsonFormat注解

    Java对象转json是Java中很常见的操作,而JsonFormat注解可以对对象中的日期字段进行格式化。下面就来详细讲解这个过程,并附带两个示例说明。 Java对象转json Java对象转json可以使用很多第三方工具库,如fastjson、Jackson、Gson等等。对于这里的讲解,我们以Jackson为例。 步骤 引入Jackson库,可以通过M…

    Java 2023年5月26日
    00
  • springMVC实现文件上传和下载

    下面我将详细讲解 Spring MVC 实现文件上传和下载的完整攻略。 文件上传 准备工作 在 Spring MVC 中,文件上传需要使用 MultipartResolver 接口来进行解析。常用的实现类有两种,分别是: StandardServletMultipartResolver:使用 Servlet API(3.0)中的 Part 接口进行文件上传解…

    Java 2023年6月15日
    00
  • Tomcatc3p0配置jnid数据源2种实现方法解析

    Tomcat+c3p0配置jndi数据源2种实现方法解析 在Java Web应用中,使用数据库是非常常见的需求。而常用的JDBC操作数据库的方式,需要手动处理连接的获取、释放、连接池的创建和维护等操作。为了简化这些操作并提供更好的性能表现,我们可以使用连接池,而c3p0就是常用的Java连接池之一。不过在Tomcat中,我们可以使用J2EE规范对数据源进行配…

    Java 2023年5月19日
    00
  • java递归算法实例分析

    Java递归算法实例分析 递归是一种常见的算法,用于解决许多数学问题、算法问题、数据结构问题等。相比于非递归算法,递归算法的代码通常更加简单易懂。本文将介绍Java中的递归算法,并通过示例说明如何使用它。 什么是递归 递归是指在函数定义中使用函数自身的方法。简单点说,就是一个函数不断地调用它自己来实现某个功能。递归函数必须有一个结束条件,否则就会陷入无限循环…

    Java 2023年5月19日
    00
  • 在js文件中如何获取basePath处理js路径问题

    获取basePath处理js路径问题是一个常见的需求。以下是如何在JS文件中获取basePath的完整攻略: 首先,在HTML文件中设置meta标签,将basePath存储到meta标签中: <head> <meta name="basePath" content="http://www.example.com…

    Java 2023年6月15日
    00
  • 微信小程序学习总结(二)样式、属性、模板操作分析

    “微信小程序学习总结(二)样式、属性、模板操作分析”是一篇关于微信小程序开发中样式、属性和模板操作的总结文章。在这篇文章中,作者讲解了小程序中涉及到的样式、属性和模板的操作方法,同时给出了一些示例,方便读者了解和掌握这些操作的具体方法。 一、样式操作: 小程序的样式操作主要涉及到对组件样式表的修改。在小程序中,我们可以通过以下两种方式来修改组件的样式: 内联…

    Java 2023年5月23日
    00
  • Spring(AbstractRoutingDataSource)实现动态数据源切换示例

    下面为你详细讲解Spring中如何使用抽象路由数据源(AbstractRoutingDataSource)实现动态数据源切换,包含两个示例。 1. 动态数据源切换 动态数据源切换指的是可以动态地选择使用哪个数据源来进行数据访问,一般用于多数据源的情况下。使用抽象路由数据源(AbstractRoutingDataSource)可以方便地实现数据源动态切换。 2…

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