Java 多线程编程之 Semaphore(构造方法、获取许可方法、释放许可方法、其他方法)

一、Semaphore

  1. Semaphore 是 Java 并发包(java.util.concurrent)中提供的一个同步工具类

  2. Semaphore 用于控制对共享资源的并发访问,它基于经典的信号量概念

  3. Semaphore 维护了一组许可证(permits),线程可以获取许可证,也可以释放许可证

  4. 如果没有可用的许可证,将阻塞线程,直到有许可证可用或线程被中断


二、构造方法

1、基本介绍
Semaphore(int permits)
  1. 创建具有给定许可数量的信号量,非公平模式
Semaphore(int permits, boolean fair)
  1. 创建具有给定许可数量的信号量,并指定公平模式
2、演示
Semaphore unfairSemaphore = new Semaphore(3);

Semaphore fairSemaphore = new Semaphore(3, true);

三、核心方法

1、获取许可
void acquire() throws InterruptedException
  1. 获取一个许可,阻塞直到获取成功或线程被中断
void acquire(int permits) throws InterruptedException
  1. 获取指定数量的许可,阻塞直到获取成功或线程被中断
boolean tryAcquire()
  1. 尝试获取一个许可,立即返回获取结果
boolean tryAcquire(int permits)
  1. 尝试获取指定数量的许可,立即返回获取结果
boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException
  1. 尝试获取一个许可,等待指定时间后返回获取结果
boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException
  1. 尝试获取指定数量的许可,等待指定时间后返回获取结果
2、释放许可
void release()
  1. 释放一个许可
void release(int permits)
  1. 释放指定数量的许可
3、演示
  1. tryAcquire() + release()
Semaphore semaphore = new Semaphore(2);

ExecutorService executor = Executors.newFixedThreadPool(4);

for (int i = 1; i <= 4; i++) {
    int id = i;
    executor.execute(() -> {
        try {
            System.out.println("线程 " + id + " 尝试获取许可...");
            semaphore.acquire();
            System.out.println("线程 " + id + " 获取许可成功,剩余许可: " + semaphore.availablePermits());

            // 模拟工作
            Thread.sleep(2000);

            System.out.println("线程 " + id + " 释放许可");
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

executor.shutdown();
# 输出结果

线程 3 尝试获取许可...
线程 1 尝试获取许可...
线程 2 尝试获取许可...
线程 4 尝试获取许可...
线程 1 获取许可成功,剩余许可: 0
线程 3 获取许可成功,剩余许可: 1
线程 1 释放许可
线程 3 释放许可
线程 2 获取许可成功,剩余许可: 1
线程 4 获取许可成功,剩余许可: 0
线程 2 释放许可
线程 4 释放许可
  1. acquire(int permits) + release(int permits)
Semaphore semaphore = new Semaphore(2);

ExecutorService executor = Executors.newFixedThreadPool(4);

for (int i = 1; i <= 4; i++) {
    int id = i;
    executor.execute(() -> {
        try {
            System.out.println("线程 " + id + " 尝试获取许可...");
            semaphore.acquire(2);
            System.out.println("线程 " + id + " 获取许可成功,剩余许可: " + semaphore.availablePermits());

            // 模拟工作
            Thread.sleep(2000);

            System.out.println("线程 " + id + " 释放许可");
            semaphore.release(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

executor.shutdown();
# 输出结果

线程 1 尝试获取许可...
线程 4 尝试获取许可...
线程 3 尝试获取许可...
线程 2 尝试获取许可...
线程 1 获取许可成功,剩余许可: 0
线程 1 释放许可
线程 2 获取许可成功,剩余许可: 0
线程 2 释放许可
线程 3 获取许可成功,剩余许可: 0
线程 3 释放许可
线程 4 获取许可成功,剩余许可: 0
线程 4 释放许可
  1. tryAcquire() + release()
Semaphore semaphore = new Semaphore(2);

ExecutorService executor = Executors.newFixedThreadPool(4);

for (int i = 1; i <= 4; i++) {
    int id = i;
    executor.execute(() -> {
        try {
            System.out.println("线程 " + id + " 尝试获取许可...");
            boolean b = semaphore.tryAcquire();
            if (!b) {
                System.out.println("线程 " + id + " 获取许可失败");
                return;
            }
            System.out.println("线程 " + id + " 获取许可成功,剩余许可: " + semaphore.availablePermits());

            // 模拟工作
            Thread.sleep(2000);

            System.out.println("线程 " + id + " 释放许可");
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

executor.shutdown();
# 输出结果

线程 4 尝试获取许可...
线程 2 尝试获取许可...
线程 1 尝试获取许可...
线程 3 尝试获取许可...
线程 1 获取许可失败
线程 3 获取许可失败
线程 2 获取许可成功,剩余许可: 0
线程 4 获取许可成功,剩余许可: 1
线程 4 释放许可
线程 2 释放许可
  1. tryAcquire(long timeout, TimeUnit unit) + release()
Semaphore semaphore = new Semaphore(2);

ExecutorService executor = Executors.newFixedThreadPool(4);

for (int i = 1; i <= 4; i++) {
    int id = i;
    executor.execute(() -> {
        try {
            System.out.println("线程 " + id + " 尝试获取许可...");
            boolean b = semaphore.tryAcquire(1, TimeUnit.SECONDS);
            if (!b) {
                System.out.println("线程 " + id + " 获取许可失败");
                return;
            }
            System.out.println("线程 " + id + " 获取许可成功,剩余许可: " + semaphore.availablePermits());

            // 模拟工作
            Thread.sleep(2000);

            System.out.println("线程 " + id + " 释放许可");
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

executor.shutdown();
# 输出结果

线程 4 尝试获取许可...
线程 2 尝试获取许可...
线程 3 尝试获取许可...
线程 1 尝试获取许可...
线程 2 获取许可成功,剩余许可: 0
线程 4 获取许可成功,剩余许可: 1
线程 1 获取许可失败
线程 3 获取许可失败
线程 4 释放许可
线程 2 释放许可
  1. tryAcquire(int permits, long timeout, TimeUnit unit) + release()
Semaphore semaphore = new Semaphore(2);

ExecutorService executor = Executors.newFixedThreadPool(4);

for (int i = 1; i <= 4; i++) {
    int id = i;
    executor.execute(() -> {
        try {
            System.out.println("线程 " + id + " 尝试获取许可...");
            boolean b = semaphore.tryAcquire(2, 1, TimeUnit.SECONDS);
            if (!b) {
                System.out.println("线程 " + id + " 获取许可失败");
                return;
            }
            System.out.println("线程 " + id + " 获取许可成功,剩余许可: " + semaphore.availablePermits());

            // 模拟工作
            Thread.sleep(2000);

            System.out.println("线程 " + id + " 释放许可");
            semaphore.release(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

executor.shutdown();
# 输出结果

线程 2 尝试获取许可...
线程 3 尝试获取许可...
线程 4 尝试获取许可...
线程 1 尝试获取许可...
线程 2 获取许可成功,剩余许可: 0
线程 4 获取许可失败
线程 3 获取许可失败
线程 1 获取许可失败
线程 2 释放许可

四、其他方法

1、基本介绍
int availablePermits()
  1. 返回当前可用的许可数量
int drainPermits()
  1. 获取并返回所有立即可用的许可
boolean isFair()
  1. 判断是否是公平模式
boolean hasQueuedThreads()
  1. 查询是否有线程正在等待获取
int getQueueLength()
  1. 返回等待获取的线程数的估计值
2、演示
  1. availablePermits()
Semaphore semaphore = new Semaphore(2);
System.out.println("初始可用许可: " + semaphore.availablePermits());

try {
    semaphore.acquire();
} catch (InterruptedException e) {
    e.printStackTrace();
}
System.out.println("获取 1 个许可后,可用许可: " + semaphore.availablePermits());
# 输出结果

初始可用许可: 2
获取 1 个许可后,可用许可: 1
  1. drainPermits()
Semaphore semaphore = new Semaphore(2);
System.out.println("初始可用许可: " + semaphore.availablePermits());

int i = semaphore.drainPermits();
System.out.println("获取 " + i + " 个许可后,可用许可: " + semaphore.availablePermits());
# 输出结果

初始可用许可: 2
获取 2 个许可后,可用许可: 0
  1. isFair()
Semaphore unfairSemaphore = new Semaphore(3);
System.out.println(unfairSemaphore.isFair());

Semaphore fairSemaphore = new Semaphore(3, true);
System.out.println(fairSemaphore.isFair());
# 输出结果

false
true
  1. hasQueuedThreads() + getQueueLength()
Semaphore semaphore = new Semaphore(1);

try {
    semaphore.acquire();
} catch (InterruptedException e) {
    e.printStackTrace();
}
System.out.println("主线程获取许可");

for (int i = 1; i <= 3; i++) {
    int id = i;
    new Thread(() -> {
        try {
            semaphore.acquire();
            System.out.println("线程" + id + "获取许可");
            semaphore.release();
            System.out.println("线程" + id + "释放许可");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }).start();
    try {
        Thread.sleep(500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

System.out.println("是否有线程在等待: " + semaphore.hasQueuedThreads());
System.out.println("等待队列长度: " + semaphore.getQueueLength());

semaphore.release();
System.out.println("主线程释放许可");

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

System.out.println("是否有线程在等待: " + semaphore.hasQueuedThreads());
System.out.println("等待队列长度: " + semaphore.getQueueLength());
# 输出结果

主线程获取许可
是否有线程在等待: true
等待队列长度: 3
主线程释放许可
线程1获取许可
线程2获取许可
线程3获取许可
线程3释放许可
线程1释放许可
线程2释放许可
是否有线程在等待: false
等待队列长度: 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值