J.U.C之AQS-Semaphore

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34203492/article/details/82498630

简单说一下Semaphore的使用

Semaphore又称信号量,是操作系统中的一个概念,在Java并发编程中,信号量控制的是线程并发的数量。Semaphore是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。把它比作是控制流量的红绿灯,比如XX马路要限制流量,只允许同时有一百辆车在这条路上行使,其他的都必须在路口等待,所以前一百辆车会看到绿灯,可以开进这条马路,后面的车会看到红灯,不能驶入XX马路,但是如果前一百辆中有五辆车已经离开了XX马路,那么后面就允许有5辆车驶入马路,这个例子里说的车就是线程,驶入马路就表示线程在执行,离开马路就表示线程执行完成,看见红灯就表示线程被阻塞,不能执行。
这里写图片描述
应用场景
Semaphore可以用于做流量控制,特别公用资源有限的应用场景,比如数据库连接。假如有一个需求,要读取几万个文件的数据,因为都是IO密集型任务,我们可以启动几十个线程并发的读取,但是如果读到内存后,还需要存储到数据库中,而数据库的连接数只有10个,这时我们必须控制只有十个线程同时获取数据库连接保存数据,否则会报错无法获取数据库连接。这个时候,我们就可以使用Semaphore来做流控。更通俗来说,比如说操场上有5个跑道,一个跑道一次只能有一个学生在上面跑步,一旦所有跑道在使用,那么后面的学生就需要等待,直到有一个学生不跑了。

上代码:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;

public class SemaphoreTest {

    private final static int threadNum = 200;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();  //创建一个线程池
        final Semaphore semaphore = new Semaphore(5);    //创建一个允许20个线程同时执行的Semaphore

        for(int i = 0; i < threadNum; i++){
            final int finalI = i;
            executorService.execute(() -> {
                try {
                    semaphore.acquire();    //获取一个执行许可  
                    //也可以semaphore.acquire(5); 表示一次获取5个许可
                    test(finalI);           //调用test方法  每次打印当前的i
                    semaphore.release();    //释放一个执行许可  
                    //也可以semaphore.release(5); 表示一次释放5个许可
                    //当每次获取的许可数和new Semaphore(i)中的i相等时  就和单线程环境一样了,这里只是举个例子
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
    }

    private static void test(int num) throws Exception{
        System.out.println(num + "--" + new SimpleDateFormat(" HH:mm:ss").format(new Date()));
        Thread.sleep(1000);
    }
}

上面代码的执行结果是:

2-- 15:59:28
5-- 15:59:28
1-- 15:59:28
0-- 15:59:28
4-- 15:59:28
6-- 15:59:29
8-- 15:59:29
10-- 15:59:29
12-- 15:59:29
16-- 15:59:29
20-- 15:59:30
24-- 15:59:30
28-- 15:59:30
32-- 15:59:30
36-- 15:59:30
.....

这里只贴出一部分 但是可以看出来 每秒都是只输出5个 因为test()方法中线程睡眠1秒
而每秒只输出5个是因为new Semaphore(5); 控制每次只能有5个线程通过

还有另一种情况,就是当前允许的并发数是5,超过5个之后就丢弃,不去管超过的,这种Semaphore也是可以控制的
看例子:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;

public class SemaphoreTest {

    private final static int threadNum = 200;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();  //创建一个线程池
        final Semaphore semaphore = new Semaphore(5);    //创建一个允许20个线程同时执行的Semaphore

        for(int i = 0; i < threadNum; i++){
            final int finalI = i;
            executorService.execute(() -> {
                try {
                    //可以设置尝试获取时间semaphore.tryAcquire(1, TimeUnit.SECONDS)   
                    //这样表示尝试获取许可  尝试时间1秒  1秒内获取到许可就执行  获取不到就不管了 
                    if(semaphore.tryAcquire()) {    //尝试获取一个许可 
                        test(finalI);           //调用test方法  每次打印当前的i
                        semaphore.release();    //释放一个执行许可
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
    }

    private static void test(int num) throws Exception{
        System.out.println(num + "--" + new SimpleDateFormat(" HH:mm:ss").format(new Date()));
        Thread.sleep(1000);
    }
}

上面这个代码输出结果是:

2-- 16:18:50
3-- 16:18:50
4-- 16:18:50
0-- 16:18:50
1-- 16:18:50

就只有5个输出 没有其他的了 因为在semaphore.tryAcquire() 这个尝试获取许可的时候 同时只允许5个 所以就只输出的5个数字 其他的都没有执行

好了 这就是简单的semaphore使用

个人浅薄理解,欢迎补充
点击链接加入群聊【Java技术学习闲聊群】:https://jq.qq.com/?_wv=1027&k=59emCBA

猜你喜欢

转载自blog.csdn.net/qq_34203492/article/details/82498630
今日推荐