java.util.concurrent包中的Semaphore类

目录

解释

使用例子:

例子1:控制同时访问某个资源的线程数量

例子2:模拟抢占停车位

总结


java.util.concurrent包中的Semaphore类解释

java.util.concurrent包中的Semaphore类是一个用于控制对共享资源访问的同步辅助类。Semaphore(信号量)的主要作用是限制对某个特定资源的访问线程数目,或者说,它用于控制并发访问共享资源的线程数量。Semaphore可以看作是一个计数器,用于跟踪可用资源的数量。

Semaphore的工作原理基于许可(permits)的概念。在创建Semaphore对象时,你可以指定一个正整数n,表示许可的初始数量。这个数量代表了在没有任何线程占用资源的情况下,可以同时访问该资源的线程数目。每次一个线程想要访问资源时,它必须先通过调用Semaphore的acquire()方法从Semaphore获得一个许可。如果Semaphore中有可用的许可,线程可以继续执行。如果没有可用的许可,线程将被阻塞,直到有许可可用或者线程被中断。

当线程完成对资源的访问后,它应该释放许可,以便其他线程可以使用。这通过调用release()方法实现。release()方法会增加Semaphore中的许可数量,如果有任何线程因为调用acquire()方法而被阻塞,并且现在有可用的许可,那么这些线程中的一个将被唤醒并允许继续执行。

Semaphore的一个常见用途是控制对某个特定资源的池(如数据库连接池)的访问。例如,如果你有一个数据库连接池,并且希望在任何给定时间最多只有10个线程可以从中获取连接,你可以创建一个初始许可数量为10的Semaphore。这样,每次一个线程想要获取一个数据库连接时,它必须先获得一个许可,这就限制了同时访问数据库连接的线程数目。

Semaphore还支持公平和非公平两种模式。在公平模式下,线程将按照它们请求许可的顺序被授予许可,这有助于避免线程饥饿问题。在非公平模式下,许可的授予顺序是不确定的,这可能会导致某些线程比其他线程更频繁地获得许可,从而提高了吞吐量,但可能会牺牲公平性。

关于java.util.concurrent包中Semaphore类的使用例子:

例子1:控制同时访问某个资源的线程数量

假设我们有一个资源,比如一个文件或者一个数据库连接,我们想要限制同时访问这个资源的线程数量。我们可以使用Semaphore来实现这一点。

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    public static void main(String[] args) {
        // 创建一个Semaphore对象,初始值为3,表示最多允许3个线程同时访问资源
        Semaphore semaphore = new Semaphore(3);

        // 创建5个线程来模拟对资源的访问
        for (int i = 1; i <= 5; i++) {
            new Thread(() -> {
                try {
                    // 尝试获取许可
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + " 获取到许可");

                    // 模拟线程执行一段时间
                    Thread.sleep(2000);

                    // 打印线程执行完毕的信息
                    System.out.println(Thread.currentThread().getName() + " 执行完毕");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 释放许可
                    semaphore.release();
                    System.out.println(Thread.currentThread().getName() + " 释放许可");
                }
            }).start();
        }
    }
}

在这个例子中,我们创建了一个初始值为3的Semaphore对象,表示最多允许3个线程同时访问资源。然后,我们创建了5个线程来模拟对资源的访问。每个线程在访问资源之前都会调用semaphore.acquire()来获取许可。如果此时没有可用的许可,线程会被阻塞,直到有许可可用。线程在访问完资源后,会调用semaphore.release()来释放许可。

例子2:模拟抢占停车位

假设我们有一个停车场,只有3个停车位,但是有6辆汽车想要停车。我们可以使用Semaphore来模拟这个场景。

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class SemaphoreDemo {
    public static void main(String[] args) {
        // 创建一个Semaphore对象,初始值为3,表示停车场有3个车位
        Semaphore semaphore = new Semaphore(3);

        // 创建6个线程模拟6辆汽车
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                try {
                    // 尝试抢占车位
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "\t抢到车位");

                    // 停留3秒钟,模拟停留时间
                    TimeUnit.SECONDS.sleep(3);

                    // 打印停留3秒后离开车位的信息
                    System.out.println(Thread.currentThread().getName() + "\t停留3秒后离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 释放车位
                    semaphore.release();
                }
            }, "汽车" + i).start();
        }
    }
}

在这个例子中,我们创建了一个初始值为3的Semaphore对象,表示停车场有3个车位。然后,我们创建了6个线程来模拟6辆汽车。每辆汽车在想要停车时都会调用semaphore.acquire()来尝试抢占车位。如果此时没有可用的车位,汽车线程会被阻塞,直到有车位可用。汽车在停留一段时间后,会调用semaphore.release()来释放车位。

这两个例子展示了Semaphore在控制对共享资源访问方面的应用。通过调整Semaphore的初始值,我们可以灵活地控制同时访问某个资源的线程数量。

如果一个类被多线程调用,则可以使用如下方法对类进行访问控制

    @Value("${calculate.semaphoreLimit:3}")
    int countLimit;

    private static Semaphore semaphore = null;

    // 初始时创建一个Semaphore对象,初始值为3,表示最多允许3个线程同时访问资源
    @PostConstruct
    public void init() {
        semaphore = new Semaphore(countLimit);
    }

总结

总的来说,Semaphore是一个强大的同步工具,它提供了一种灵活的方式来控制对共享资源的并发访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

chen2017sheng

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值