当前位置:首页 > 技术 > 正文内容

Java并发编程中的七种锁机制详解

访客 技术 2026年7月4日 1

为何需要锁机制

在多线程环境中,当多个线程同时访问共享资源时,可能会引发数据不一致的问题。例如经典的i++操作,在并发环境下可能得不到预期结果。锁的作用类似于现实生活中的权限管理,它确保同一时刻只有一个线程能够访问特定资源,从而保障数据的安全性。

七种常见锁机制解析

1. synchronized内置锁

synchronized是Java中最基础的同步机制,它可以修饰方法或代码块。当线程进入被synchronized修饰的区域时会自动获得锁,退出时自动释放锁。

public class SyncDemo {
    public synchronized void doSomething() {
        System.out.println(Thread.currentThread().getName() + " 正在执行");
    }
    
    public void doAnotherThing() {
        synchronized(this) {
            System.out.println(Thread.currentThread().getName() + " 正在执行");
        }
    }
}

2. ReentrantLock可重入锁

ReentrantLock提供了比synchronized更灵活的锁定机制,支持公平锁、超时获取锁等功能。需要注意的是,必须手动释放锁以避免死锁。

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {
    private final ReentrantLock lock = new ReentrantLock();
    
    public void performTask() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " 获得锁");
            nestedOperation();
        } finally {
            lock.unlock();
            System.out.println(Thread.currentThread().getName() + " 释放锁");
        }
    }
    
    private void nestedOperation() {
        lock.lock();
        try {
            System.out.println("嵌套操作");
        } finally {
            lock.unlock();
        }
    }
}

3. ReadWriteLock读写锁

读写锁将锁分为读锁和写锁两种类型。允许多个线程同时进行读操作,但在写操作期间禁止任何读写操作。

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

public class RWLDemo {
    private final ReadWriteLock rwl = new ReentrantReadWriteLock();
    private int value = 0;
    
    public int getValue() {
        rwl.readLock().lock();
        try {
            return value;
        } finally {
            rwl.readLock().unlock();
        }
    }
    
    public void setValue(int val) {
        rwl.writeLock().lock();
        try {
            value = val;
        } finally {
            rwl.writeLock().unlock();
        }
    }
}

4. StampedLock高性能锁

StampedLock是一种更为高效的读写锁实现,支持乐观读模式。在这种模式下,读操作不需要阻塞写操作,但需要验证数据一致性。

import java.util.concurrent.locks.StampedLock;

public class StampedLockDemo {
    private final StampedLock sl = new StampedLock();
    private double x, y;
    
    public void move(double dx, double dy) {
        long stamp = sl.writeLock();
        try {
            x += dx;
            y += dy;
        } finally {
            sl.unlockWrite(stamp);
        }
    }
    
    public double getDistance() {
        long stamp = sl.tryOptimisticRead();
        double currentX = x, currentY = y;
        if (!sl.validate(stamp)) {
            stamp = sl.readLock();
            try {
                currentX = x;
                currentY = y;
            } finally {
                sl.unlockRead(stamp);
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }
}

5. Semaphore信号量

Semaphore用于控制同时访问特定资源的线程数量。通过许可令牌的方式限制并发访问数。

import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    private final Semaphore sem = new Semaphore(3);
    
    public void useResource() {
        try {
            sem.acquire();
            System.out.println(Thread.currentThread().getName() + " 使用资源");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            sem.release();
            System.out.println(Thread.currentThread().getName() + " 释放资源");
        }
    }
}

6. CountDownLatch倒计时器

CountDownLatch允许一个或多个线程等待其他线程完成操作。初始化时设定计数值,每当有线程完成任务就调用countDown()减少计数,当计数为零时唤醒等待线程。

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);
        
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " 完成任务");
                latch.countDown();
            }).start();
        }
        
        latch.await();
        System.out.println("所有任务已完成");
    }
}

7. CyclicBarrier循环屏障

CyclicBarrier使得一组线程相互等待,直到所有线程都到达屏障点后再继续执行。与CountDownLatch不同的是,它可以重复使用。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(3, () -> 
            System.out.println("所有参与者已就位"));
            
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " 到达屏障");
                    barrier.await();
                    System.out.println(Thread.currentThread().getName() + " 继续执行");
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

锁机制选择指南

锁类型 主要特征 推荐使用场景 优势 劣势
synchronized 自动加锁解锁 基本同步需求 语法简单,自动管理 功能有限
ReentrantLock 手动控制锁 复杂同步逻辑 支持超时、中断等 需手动释放
ReadWriteLock 读写分离 读多写少场景 提升读并发性能 写操作影响读
StampedLock 乐观读支持 极高读频场景 极致读性能 逻辑相对复杂
Semaphore 并发数量控制 资源池、限流 精确控制并发数 非直接同步方案
CountDownLatch 一次性等待 前置任务等待 简单高效 不可重复使用
CyclicBarrier 循环等待集合 阶段性协作任务 可重复利用 要求全员参与
标签: JavaConcurrency

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。