【并发编程】- Semaphore动态修改permits许可

346 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

Semaphore构造方法permits参数作用

参数permits的作用是设置许可的个数,当传入大于1的许可,代表同一时间内,主最多允许有X个线程可以执行acquire()和release()之间的代码。

修改SemaphoreService类的许可个数如下:

@Slf4j
public class SemaphoreService {
    private Semaphore semaphore = new Semaphore(2);
    
    public void testSemaphore(){
            semaphore.acquire();
            log.info("线程名:{}-开始执行时间:{}",Thread.currentThread().getName(),System.currentTimeMillis());
			Thread.sleep(5000);
            log.info("线程名:{}-结束执行时间:{}",Thread.currentThread().getName(),System.currentTimeMillis());
            semaphore.release();
    }
}

重新执行运行类结果如下:

14:55:49.355 [B] INFO com.ozx.concurrentprogram.semaphore.service.SemaphoreService - 线程名:B-开始执行时间:1648882549325
14:55:49.350 [A] INFO com.ozx.concurrentprogram.semaphore.service.SemaphoreService - 线程名:A-开始执行时间:1648882549318
14:55:54.344 [B] INFO com.ozx.concurrentprogram.semaphore.service.SemaphoreService - 线程名:B-结束执行时间:1648882554344
14:55:54.345 [C] INFO com.ozx.concurrentprogram.semaphore.service.SemaphoreService - 线程名:C-开始执行时间:1648882554345
14:55:54.417 [A] INFO com.ozx.concurrentprogram.semaphore.service.SemaphoreService - 线程名:A-结束执行时间:1648882554417
14:55:55.480 [C] INFO com.ozx.concurrentprogram.semaphore.service.SemaphoreService - 线程名:C-结束执行时间:1648882555480

由此可以看出同一时间只有2个线程可以同时执行acquire()和release()之间的代码。

对于SemaphoreService类的构造方法传递的参数permits值大于1时,该类不能保证线程安全性,因为有可能出现多个线程共同访问实例变量,导致出现脏数据的情况。

方法acquire(int permits)参数作用及动态添加permits许可数量

有参方法acquire(int permits)的功能是每调用1次此方法,就使用x个许可。

创建多个许可获取或释放的类代码如下:

@Slf4j
public class SemaphoreService {
    private Semaphore semaphore = new Semaphore(10);

    public void testSemaphore(){

        try {
            semaphore.acquire(2);
            log.info("线程名:{}-开始执行时间:{}",Thread.currentThread().getName(),System.currentTimeMillis());
            int sleepTime = (int)(Math.random() * 10000);
            log.info("线程名:{}-休眠时间:{} 秒",Thread.currentThread().getName(),sleepTime/1000);
            Thread.sleep((int)Math.random()*1000);
            log.info("线程名:{}-结束执行时间:{}",Thread.currentThread().getName(),System.currentTimeMillis());
            semaphore.release(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}