【多线程】Semphore工具

1.构造方法

//创建一个 Semaphore与给定数量的许可证和nonfair公平设置。
Semaphore(int permits)
//创建一个允许给定数量 Semaphore和给定的公平环境。
Semaphore(int permits, boolean fair) 

参数介绍:

  • permits:表示当前的凭证数量
  • fair:表示当前是不是平等的(FIFO)先进先出,设置为false是表示可以插队的,比如现在三个Thread在等待permits,但是后到的竟然比我先拿到permits,这就是插队。

2.核心方法

使用semaphore可以给线程颁发一个凭证,只有获得凭证的线程才能运行,如果没有获得那就阻塞当前线程,等待其他人释放凭证才行。

其实在semaphore内部只是维护了一个count,而并不是什么凭证。我们在设置count大小时就是指定了凭证的多少。

public void acquire();//获取凭证
public void release();//释放凭证
public void acquire(int permits);//获取凭证
public void release(int permits);//获取凭证
public boolean tryAcquire();//尝试获取1个凭证
public boolean tryAcquire(int permits);//尝试获取多个凭证
public boolean tryAcquire(int permits, long timeout, TimeUnit unit);//在特定时间内获取指定个数的凭证

在尝试获取凭证时一定注意判断是不是真正的获得到了凭证,如果没有获得就不要去释放,否则会导致permits总数量改变

3.代码测试

acquire(),和release()简单的代码测试:如下有10个线程,每个线程需要1个凭证,所以同时只能运行5个线程,后面的线程只能等待别人释放才能运行。

public class MyDemo {
    private static final Semaphore SEMAPHORE = new Semaphore(5);
    public static void main(String[] args){
        IntStream.rangeClosed(0,9).forEach(i -> {
            new Thread(()->{
                //拿到一个凭证
                try {
                    System.out.println(Thread.currentThread().getName() + "start running ");
                    SEMAPHORE.acquire();
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName() + "finished ");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    SEMAPHORE.release();
                }
            }).start();
        });
    }
}

4.使用Semaphore实现简单的锁

public static void main(String[] args) {
    MyLock myLock = new MyLock();
    IntStream.rangeClosed(0,3).forEach(i -> {
        new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "执行开始!!!!");
            try {
                myLock.lock();
                System.out.println(Thread.currentThread().getName() + "拿到了锁");
                TimeUnit.SECONDS.sleep(5L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                System.out.println(Thread.currentThread().getName() + "释放了锁");
                myLock.unlock();
            }
        },"Thread - "+(i+1)).start();
    });
}

static class MyLock{
    private final Semaphore semaphore = new Semaphore(1);

    public void lock() throws InterruptedException{
        semaphore.acquire();
    }

    public void unlock(){
        semaphore.release();
    }

}

5.使用场景

假设有多线程去执行同一任务,但是某一时刻我只想让固定大小的线程去执行,就可以使用semaphore,来限制并发的线程数。

public static void main(String[] args) {
    Semaphore semaphore = new Semaphore(2);
    new Thread(()->{
        try {
            semaphore.acquire(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            semaphore.release(3);
        }
    }).start();
}

6.注意事项

1.不论当前线程有没有获得到凭证,只要调用了acquire就会导致permits增加,所以在使用时要细心注意

如下代码所示,只获取两个凭证,但是释放了5个,所以最后结果凭证变成了6个

public class MyDemo {
    private static final Semaphore SEMAPHORE = new Semaphore(3);
    public static void main(String[] args) throws InterruptedException {
        System.out.println(SEMAPHORE.availablePermits());
        SEMAPHORE.acquire(2);
        SEMAPHORE.release(5);
        System.out.println(SEMAPHORE.availablePermits());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值