解析 Java 的多线程同步机制:锁与信号量

目录

引言

锁机制

基本概念

内置锁(synchronized 关键字)

重入锁(ReentrantLock)

信号量机制

基本概念

Java 中的信号量(Semaphore)

锁与信号量的比较

功能侧重点

使用场景

总结


 

引言

在 Java 编程里,多线程能够显著提升程序的性能与响应速度。不过,多个线程同时访问共享资源时,可能会引发数据不一致、竞态条件等问题。为了确保线程安全,Java 提供了多种多线程同步机制,其中锁和信号量是较为常用的两种。接下来,我们会深入探讨这两种机制。

锁机制

基本概念

锁是一种用于控制多个线程对共享资源访问的同步机制。当一个线程获取到锁之后,其他线程就必须等待该线程释放锁,才能继续访问共享资源。这样可以保证同一时刻只有一个线程能访问共享资源,避免数据不一致的问题。

内置锁(synchronized 关键字)

  • 用法synchronized 关键字可以修饰方法或者代码块。当修饰方法时,该方法在同一时刻只能被一个线程访问;当修饰代码块时,需要指定一个锁对象,只有获取到该锁对象的线程才能执行代码块中的内容。
  • 示例代码

 

public class SynchronizedExample {
    private int count = 0;

    // 同步方法
    public synchronized void increment() {
        count++;
    }

    // 同步代码块
    public void decrement() {
        synchronized (this) {
            count--;
        }
    }
}

 

  • 原理:每个 Java 对象都有一个与之关联的监视器(monitor),synchronized 方法或者代码块在进入时会尝试获取对象的监视器,获取成功才能执行,执行完毕后释放监视器。

重入锁(ReentrantLock)

  • 用法ReentrantLock 是 Java 提供的一个可重入的互斥锁,它比 synchronized 关键字更加灵活。可以通过 lock() 方法获取锁,通过 unlock() 方法释放锁。
  • 示例代码

 

import java.util.concurrent.locks.ReentrantLock;

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

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

 

  • 特点:可重入意味着同一个线程可以多次获取同一把锁而不会被阻塞;还支持公平锁模式,即按照线程请求锁的顺序来分配锁。

信号量机制

基本概念

信号量是一种更高级的同步机制,它可以控制同时访问共享资源的线程数量。信号量内部维护了一个许可(permit)计数器,线程在访问共享资源之前需要先获取许可,访问结束后释放许可。

Java 中的信号量(Semaphore)

  • 用法Semaphore 类位于 java.util.concurrent 包中,通过构造函数指定初始的许可数量。线程可以通过 acquire() 方法获取许可,通过 release() 方法释放许可。
  • 示例代码
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private static Semaphore semaphore = new Semaphore(2);

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + " 获取到许可,开始访问资源");
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + " 访问资源结束,释放许可");
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

 

  • 应用场景:适用于需要限制并发访问数量的场景,比如数据库连接池,通过信号量可以限制同时获取数据库连接的线程数量。

锁与信号量的比较

功能侧重点

  • :主要用于实现互斥访问,确保同一时刻只有一个线程能访问共享资源,侧重于保护数据的一致性。
  • 信号量:更侧重于控制并发访问的线程数量,可以允许多个线程同时访问共享资源,但数量是有限制的。

使用场景

  • :适用于对共享资源进行独占访问的场景,例如对全局变量的修改、对文件的读写操作等。
  • 信号量:适用于需要限制并发访问数量的场景,如资源池的管理、限流等。

总结

锁和信号量都是 Java 中重要的多线程同步机制,它们各自有不同的特点和适用场景。在实际开发中,需要根据具体的需求来选择合适的同步机制,以确保程序的线程安全和性能。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潜意识Java

源码一定要私信我,有问题直接问

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值