用synchronized实现Semaphore

Posted zhujm320

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用synchronized实现Semaphore相关的知识,希望对你有一定的参考价值。

介绍

基于Semaphore的功能,主要用来实现并发和限流,本文采用synchronized来实现Semaphore基础功能。关于Semaphore的说明,请参考JDK1.8 信号量(Semaphore)的基本使用

代码实现

public class MySemaphore {

    private volatile int count;
    private volatile int waitCount = 0;

    /**
     * 初始化信号量
     * @param count
     */
    public MySemaphore(int count) {
        this.count = count;
    }

    /**
     * 获取信号量
     * @throws InterruptedException
     */
    public void acquire() throws InterruptedException {
        while (true) {
            //大量线程在此处等锁
            //执行wait的线程被唤醒后, 重新加入抢锁操作
            waitCount++;
            synchronized (this) {
                if (this.count > 0) {
                    this.count--;
                    waitCount--;
                    break;
                }
                this.wait();
            }
            waitCount--;
            //退出synchronized代码块,释放锁
        }
    }

    /**
     * 释放锁,通知所有等待线程进行抢锁
     */
    public void release() {
        synchronized (this) {
            this.count++;
            this.notifyAll();
        }
    }

    /**
     * 可用的信号量
     * @return
     */
    public int availablePermits(){
        return this.count;
    }

    /**
     * 阻塞线程的个数
     * @return
     */
    public int getQueueLength(){
        return waitCount;
    }
}

上述代码主要实现了acquire(),release(),availablePermits()和getQueueLength()最基础的功能。

测试代码

package sample;

import java.util.concurrent.Semaphore;

public class SemaphoreTest {



    public static void main(String[] args) {

//        Semaphore semaphore=new Semaphore(24);
        MySemaphore semaphore = new MySemaphore(24);

//        int count = semaphore.availablePermits();
//        System.out.println("可用信号量 count1: " + count);
//        //增加20个信号量
//        semaphore.release(20);
        int count = semaphore.availablePermits();
        //此时信号量个数为24个, 可以支持同时跑24个线程
        System.out.println("可用信号量 count2: " + count);
        for (int i = 0; i < 200; i ++){
            new Thread(()->{
                try {
                    semaphore.acquire();
                    System.out.println("" + Thread.currentThread().getName() + " 进入" + " 时间: " + System.currentTimeMillis());
                    Thread.sleep(200);
                    System.out.println("" + Thread.currentThread().getName() + " 退出" + " 时间: " + System.currentTimeMillis());
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "线程"+i).start();
        }
        //延迟一下等待获取信号量的线程全部进入等待队列
        try{
            Thread.sleep(10);
        }catch (Exception e){
            e.printStackTrace();
        }
        int waitT = semaphore.getQueueLength();
        System.out.println("等待线程个数: " + waitT + " 时间: " + System.currentTimeMillis());
    }
}

测试结果

可用信号量 count2: 24
线程0 进入 时间: 1621162349849
线程3 进入 时间: 1621162349849
线程6 进入 时间: 1621162349850
线程1 进入 时间: 1621162349850
线程4 进入 时间: 1621162349850
线程9 进入 时间: 1621162349850
线程2 进入 时间: 1621162349850
线程16 进入 时间: 1621162349850
线程8 进入 时间: 1621162349851
线程10 进入 时间: 1621162349851
线程25 进入 时间: 1621162349851
线程5 进入 时间: 1621162349851
线程29 进入 时间: 1621162349851
线程31 进入 时间: 1621162349851
线程33 进入 时间: 1621162349851
线程15 进入 时间: 1621162349851
线程7 进入 时间: 1621162349851
线程17 进入 时间: 1621162349851
线程39 进入 时间: 1621162349852
线程18 进入 时间: 1621162349852
线程20 进入 时间: 1621162349852
线程21 进入 时间: 1621162349852
线程22 进入 时间: 1621162349855
线程23 进入 时间: 1621162349855
等待线程个数: 176 时间: 1621162349885
线程20 退出 时间: 1621162350059
线程5 退出 时间: 1621162350059
线程22 退出 时间: 1621162350059
线程0 退出 时间: 1621162350059
线程31 退出 时间: 1621162350059
线程6 退出 时间: 1621162350059
线程3 退出 时间: 1621162350059
线程4 退出 时间: 1621162350059
线程16 退出 时间: 1621162350059
线程17 退出 时间: 1621162350059
线程29 退出 时间: 1621162350059
线程9 退出 时间: 1621162350059
线程157 进入 时间: 1621162350059
线程15 退出 时间: 1621162350059
线程33 退出 时间: 1621162350059
线程25 退出 时间: 1621162350059
线程21 退出 时间: 1621162350059
线程39 退出 时间: 1621162350059
线程18 退出 时间: 1621162350059
线程8 退出 时间: 1621162350059
线程127 进入 时间: 1621162350060
线程10 退出 时间: 1621162350059
线程131 进入 时间: 1621162350060
线程135 进入 时间: 1621162350060
线程139 进入 时间: 1621162350060
线程143 进入 时间: 1621162350060
线程145 进入 时间: 1621162350059
线程148 进入 时间: 1621162350059
线程162 进入 时间: 1621162350059
线程166 进入 时间: 1621162350059
线程168 进入 时间: 1621162350059
线程173 进入 时间: 1621162350059
线程180 进入 时间: 1621162350059
线程186 进入 时间: 1621162350059
线程190 进入 时间: 1621162350059
线程195 进入 时间: 1621162350059
线程197 进入 时间: 1621162350059
线程198 进入 时间: 1621162350059
线程199 进入 时间: 1621162350059
线程2 退出 时间: 1621162350059
线程7 退出 时间: 1621162350059
线程1 退出 时间: 1621162350059
线程23 退出 时间: 1621162350059
线程60 进入 时间: 1621162350062
线程51 进入 时间: 1621162350062
线程77 进入 时间: 1621162350062
线程121 进入 时间: 1621162350060
线程61 进入 时间: 1621162350062
线程143 退出 时间: 1621162350261
线程131 退出 时间: 1621162350261
线程139 退出 时间: 1621162350261
线程135 退出 时间: 1621162350261
线程127 退出 时间: 1621162350261
线程157 退出 时间: 1621162350261
线程178 进入 时间: 1621162350261
线程185 进入 时间: 1621162350261
线程191 进入 时间: 1621162350261
线程194 进入 时间: 1621162350261
线程196 进入 时间: 1621162350261
线程175 进入 时间: 1621162350261
线程61 退出 时间: 1621162350276
线程190 退出 时间: 1621162350276
线程121 退出 时间: 1621162350276
线程193 进入 时间: 1621162350276
线程77 退出 时间: 1621162350276
线程148 退出 时间: 1621162350276
线程166 退出 时间: 1621162350276
线程145 退出 时间: 1621162350276
线程51 退出 时间: 1621162350276
线程11 进入 时间: 1621162350276
线程52 进入 时间: 1621162350276
线程49 进入 时间: 1621162350276
线程179 进入 时间: 1621162350276
线程192 进入 时间: 1621162350276
线程189 进入 时间: 1621162350276
线程198 退出 时间: 1621162350276
线程199 退出 时间: 1621162350276
线程186 退出 时间: 1621162350276
线程173 退出 时间: 1621162350276
线程180 退出 时间: 1621162350276
线程197 退出 时间: 1621162350276
线程168 退出 时间: 1621162350276
线程60 退出 时间: 1621162350276
线程162 退出 时间: 1621162350276
线程195 退出 时间: 1621162350276
线程99 进入 时间: 1621162350277
线程95 进入 时间: 1621162350277
线程91 进入 时间: 1621162350277
线程90 进入 时间: 1621162350277
线程85 进入 时间: 1621162350277
线程80 进入 时间: 1621162350277
线程75 进入 时间: 1621162350277
线程71 进入 时间: 1621162350277
线程66 进入 时间: 1621162350276
线程30 进入 时间: 1621162350276
线程104 进入 时间: 1621162350277
线程178 退出 时间: 1621162350464
线程175 退出 时间: 1621162350464
线程194 退出 时间: 1621162350464
线程196 退出 时间: 1621162350464
线程191 退出 时间: 1621162350464
线程185 退出 时间: 1621162350464
线程48 进入 时间: 1621162350464
线程45 进入 时间: 1621162350465
线程176 进入 时间: 1621162350464
线程183 进入 时间: 1621162350464
线程187 进入 时间: 1621162350464
线程188 进入 时间: 1621162350464
线程30 退出 时间: 1621162350480
线程90 退出 时间: 1621162350480
线程95 退出 时间: 1621162350480
线程184 进入 时间: 1621162350480
线程52 退出 时间: 1621162350480
线程91 退出 时间: 1621162350480
线程49 退出 时间: 1621162350480
线程189 退出 时间: 1621162350480
线程193 退出 时间: 1621162350480
线程80 退出 时间: 1621162350480
线程124 进入 时间: 1621162350480
线程75 退出 时间: 1621162350480
线程99 退出 时间: 1621162350480
线程104 退出 时间: 1621162350480
线程85 退出 时间: 1621162350480
线程150 进入 时间: 1621162350480
线程140 进入 时间: 1621162350480
线程136 进入 时间: 1621162350480
线程126 进入 时间: 1621162350480
线程118 进入 时间: 1621162350480
线程114 进入 时间: 1621162350480
线程109 进入 时间: 1621162350480
线程28 进入 时间: 1621162350480
线程181 进入 时间: 1621162350480
线程182 进入 时间: 1621162350480
线程192 退出 时间: 1621162350480
线程11 退出 时间: 1621162350480
线程179 退出 时间: 1621162350480
线程66 退出 时间: 1621162350480
线程71 退出 时间: 1621162350480
线程42 进入 时间: 1621162350481
线程55 进入 时间: 1621162350481
线程54 进入 时间: 1621162350481
线程58 进入 时间: 1621162350481
线程153 进入 时间: 1621162350480
线程38 进入 时间: 1621162350481
线程45 退出 时间: 1621162350667
线程176 退出 时间: 1621162350667
线程48 退出 时间: 1621162350667
线程59 进入 时间: 1621162350667
线程177 进入 时间: 1621162350667
线程50 进入 时间: 1621162350667
线程183 退出 时间: 1621162350682
线程55 退出 时间: 1621162350682
线程109 退出 时间: 1621162350682
线程124 退出 时间: 1621162350682
线程184 退出 时间: 1621162350682
线程182 退出 时间: 1621162350682
线程181 退出 时间: 1621162350682
线程150 退出 时间: 1621162350682
线程54 退出 时间: 1621162350682
线程58 退出 时间: 1621162350682
线程153 退出 时间: 1621162350682
线程42 退出 时间: 1621162350682
线程28 退出 时间: 1621162350682
线程114 退出 时间: 1621162350682
线程188 退出 时间: 1621162350682
线程118 退出 时间: 1621162350682
线程187 退出 时间: 1621162350682
线程126 退出 时间: 1621162350682
线程152 进入 时间: 1621162350682
线程160 进入 时间: 1621162350682
线程164 进入 时间: 1621162350682
线程171 进入 时间: 1621162350682
线程102 进入 时间: 1621162350682
线程97 进入 时间: 1621162350682
线程92 进入 时间: 1621162350682
线程84 进入 时间: 1621162350682
线程78 进入 时间: 1621162350682
线程70 进入 时间: 1621162350682
线程63 进入 时间: 1621162350682
线程64 进入 时间: 1621162350682
线程19 进入 时间: 1621162350682
线程32 进入 时间: 1621162350682
线程14 进入 时间: 1621162350682
线程35 进入 时间: 1621162350682
线程56 进入 时间: 1621162350682
线程136 退出 时间: 1621162350682
线程140 退出 时间: 1621162350682
线程38 退出 时间: 1621162350682
线程86 进入 时间: 1621162350683
线程89 进入 时间: 1621162350683
线程146 进入 时间: 1621162350682
线程79 进入 时间: 1621162350683
线程177 退出 时间: 1621162350868
线程50 退出 时间: 1621162350868
线程59 退出 时间: 1621162350868
线程144 进入 时间: 1621162350868
线程141 进入 时间: 1621162350868
线程142 进入 时间: 1621162350868
线程56 退出 时间: 1621162350884
线程102 退出 时间: 1621162350884
线程152 退出 时间: 1621162350884
线程164 退出 时间: 1621162350884
线程97 退出 时间: 1621162350884
线程19 退出 时间: 1621162350884
线程92 退出 时间: 1621162350884
线程160 退出 时间: 1621162350884
线程84 退出 时间: 1621162350884
线程63 退出 时间: 1621162350884
线程35 退出 时间: 1621162350884
线程70 退出 时间: 1621162350884
线程171 退出 时间: 1621162350884
线程32 退出 时间: 1621162350884
线程78 退出 时间: 1621162350884
线程14 退出 时间: 1621162350884
线程64 退出 时间: 1621162350884
线程112 进入 时间: 1621162350885
线程108 进入 时间: 1621162350885
线程24 进入 时间: 1621162350885
线程149 进入 时间: 1621162350885
线程155 进入 时间: 1621162350884
线程159 进入 时间: 1621162350884
线程169 进入 时间: 1621162350884
线程103 进入 时间: 1621162350884
线程94 进入 时间: 1621162350884
线程87 进入 时间: 1621162350884
线程13 进入 时间: 1621162350884
线程40 进入 时间: 1621162350884
线程57 进入 时间: 1621162350884
线程67 进入 时间: 1621162350884
线程65 进入 时间: 1621162350884
线程74 进入 时间: 1621162350884
线程76 进入 时间: 1621162350884
线程89 退出 时间: 1621162350899
线程79 退出 时间: 1621162350899
线程146 退出 时间: 1621162350899
线程86 退出 时间: 1621162350899
线程43 进入 时间: 1621162350899
线程62 进入 时间: 1621162350899
线程73 进入 时间: 1621162350899
线程36 进入 时间: 1621162350899
线程144 退出 时间: 1621162351071
线程141 退出 时间: 1621162351071
线程72 进入 时间: 1621162351071
线程142 退出 时间: 1621162351071
线程53 进入 时间: 1621162351071
线程37 进入 时间: 1621162351071
线程57 退出 时间: 1621162351087
线程87 退出 时间: 1621162351087
线程169 退出 时间: 1621162351087
线程108 退出 时间: 1621162351087
线程13 退出 时间: 1621162351087
线程103 退出 时间: 1621162351087
线程67 退出 时间: 1621162351087
线程74 退出 时间: 1621162351087
线程149 退出 时间: 1621162351087
线程24 退出 时间: 1621162351087
线程76 退出 时间: 1621162351087
线程65 退出 时间: 1621162351087
线程155 退出 时间: 1621162351087
线程132 进入 时间: 1621162351087
线程138 进入 时间: 1621162351087
线程106 进入 时间: 1621162351087
线程147 进入 时间: 1621162351087
线程156 进入 时间: 1621162351087
线程165 进入 时间: 1621162351087
线程101 进入 时间: 1621162351087
线程93 进入 时间: 1621162351087
线程81 进入 时间: 1621162351087
线程44 进入 时间: 1621162351087
线程68 进入 时间: 1621162351087
线程69 进入 时间: 1621162351087
线程112 退出 时间: 1621162351087
线程94 退出 时间: 1621162351087
线程159 退出 时间: 1621162351087
线程40 退出 时间: 1621162351087
线程96 进入 时间: 1621162351088
线程172 进入 时间: 1621162351088
线程34 进入 时间: 1621162351088
线程27 进入 时间: 1621162351088
线程129 进入 时间: 1621162351087
线程36 退出 时间: 1621162351102
线程43 退出 时间: 1621162351102
线程62 退出 时间: 1621162351102
线程73 退出 时间: 1621162351102
线程88 进入 时间: 1621162351102
线程26 进入 时间: 1621162351102
线程41 进入 时间: 1621162351102
线程123 进入 时间: 1621162351102
线程53 退出 时间: 1621162351274
线程37 退出 时间: 1621162351274
线程72 退出 时间: 1621162351274
线程98 进入 时间: 1621162351274
线程12 进入 时间: 1621162351274
线程128 进入 时间: 1621162351274
线程27 退出 时间: 1621162351289
线程93 退出 时间: 1621162351289
线程138 退出 时间: 1621162351289
线程101 退出 时间: 1621162351289
线程165 退出 时间: 1621162351289
线程147 退出 时间: 1621162351289
线程96 退出 时间: 1621162351289
线程132 退出 时间: 1621162351289
线程68 退出 时间: 1621162351289
线程44 退出 时间: 1621162351289
线程34 退出 时间: 1621162351289
线程134 进入 时间: 1621162351289
线程133 进入 时间: 1621162351289
线程156 退出 时间: 1621162351289
线程110 进入 时间: 1621162351289
线程129 退出 时间: 1621162351289
线程107 进入 时间: 1621162351289
线程158 进入 时间: 1621162351289
线程161 进入 时间: 1621162351289
线程47 进入 时间: 1621162351289
线程137 进入 时间: 1621162351289
线程113 进入 时间: 1621162351289
线程119 进入 时间: 1621162351289
线程83 进入 时间: 1621162351289
线程82 进入 时间: 1621162351289
线程106 退出 时间: 1621162351289
线程81 退出 时间: 1621162351289
线程69 退出 时间: 1621162351289
线程172 退出 时间: 1621162351289
线程105 进入 时间: 1621162351291
线程122 进入 时间: 1621162351291
线程130 进入 时间: 1621162351290
线程154 进入 时间: 1621162351290
线程163 进入 时间: 1621162351291
线程123 退出 时间: 1621162351304
线程115 进入 时间: 1621162351304
线程41 退出 时间: 1621162351304
线程26 退出 时间: 1621162351304
线程88 退出 时间: 1621162351304
线程100 进入 时间: 1621162351304
线程170 进入 时间: 1621162351304
线程111 进入 时间: 1621162351304
线程12 退出 时间: 1621162351475
线程128 退出 时间: 1621162351475
线程98 退出 时间: 1621162351475
线程117 进入 时间: 1621162351475
线程174 进入 时间: 1621162351475
线程151 进入 时间: 1621162351475
线程134 退出 时间: 1621162351490
线程133 退出 时间: 1621162351490
线程120 进入 时间: 1621162351490
线程46 进入 时间: 1621162351490
线程154 退出 时间: 1621162351505
线程113 退出 时间: 1621162351505
线程116 进入 时间: 1621162351505
线程100 退出 时间: 1621162351505
线程167 进入 时间: 1621162351505
线程107 退出 时间: 1621162351505
线程161 退出 时间: 1621162351505
线程47 退出 时间: 1621162351505
线程115 退出 时间: 1621162351505
线程111 退出 时间: 1621162351505
线程170 退出 时间: 1621162351505
线程137 退出 时间: 1621162351505
线程83 退出 时间: 1621162351505
线程82 退出 时间: 1621162351505
线程110 退出 时间: 1621162351505
线程119 退出 时间: 1621162351505
线程158 退出 时间: 1621162351505
线程122 退出 时间: 1621162351505
线程130 退出 时间: 1621162351505
线程163 退出 时间: 1621162351505
线程105 退出 时间: 1621162351505
线程125 进入 时间: 1621162351505
线程117 退出 时间: 1621162351678
线程151 退出 时间: 1621162351678
线程174 退出 时间: 1621162351678
线程46 退出 时间: 1621162351694
线程120 退出 时间: 1621162351694
线程125 退出 时间: 1621162351709
线程116 退出 时间: 1621162351709
线程167 退出 时间: 1621162351709

Process finished with exit code 0

通过测试,MySemaphore基本实现了线程同步和限流作用,测试结果与Semaphore一致。

 

 

 

以上是关于用synchronized实现Semaphore的主要内容,如果未能解决你的问题,请参考以下文章

Semaphore实现原理分析

关于Semaphore

关于Semaphore

Semaphore替换多线程synchronized解决并发环境死锁,Java

synchronizedlocksemaphoreblockingqueue实现生产消费场景。

第4章 同步控制 Synchronization ----信号量(Semaphore)