Semaphore of JDK by hand

Pre-thinking

First of all, make it clear that peak shaving and current limiting do not necessarily have to use MQ queues. In fact, JDK provides us with a good environment. Semaphore's main function is to [time for space], which is the request that we can't handle now. Let him wait a moment. Yes, after we have free space to deal with him, here is mainly because the JDK has already achieved peak-shaving and current-limiting, so we can make ourselves more profound.

The main idea

Semaphore is nothing more than putting requests that cannot be processed into the queue and taking them out when they can be processed.

Mainly used classes

  • LinkedBlockingQueue: Of course, the queue is indispensable here, of course, this queue has another function, whoever puts the token back
  • AtomicInteger: Mainly determine when to block
  • LockSupport: switch thread state

The explanation is over! !

/**
     * 用于存储线程
     */
    private LinkedBlockingQueue<Thread> requestQueue = new LinkedBlockingQueue<>();
    /**
     * 外部传入令牌数量,用于什么时候让线程进入阻塞
     */
    private AtomicInteger tokenNumber;

    public MySemaphore(Integer tokenNumber) {
    
    
        this.tokenNumber = new AtomicInteger(tokenNumber);
    }

This step has nothing to say to continue! !

/**
     * 是否能获取令牌
     */
    public boolean tryAcquire() {
    
    
        if (!requestQueue.contains(Thread.currentThread())) {
    
    
            requestQueue.add(Thread.currentThread());
        }
        return tokenNumber.get() > 0;
    }

Mainly determine whether the token can be obtained, and do not put duplicate threads in the queue

/**
     * 获取令牌
     */
    public void acquire() {
    
    
        //当前令牌捅中还有令牌,则进行自减,没有则阻塞进入等待队列
        if ( tryAcquire()) {
    
    
            tokenNumber.decrementAndGet();
        } else {
    
    
            LockSupport.park();
        }
    }

Obtain a token, set the token in the barrel to -1, if not, block

/**
     * 用完了释放令牌 只有是当前队列中的线程才允许释放令牌,并且检测是否在休眠线程,是则唤醒
     */
    public void release() {
    
    
        if (requestQueue.remove(Thread.currentThread())) {
    
    
            tokenNumber.incrementAndGet();
            for (Thread thread : requestQueue) {
    
    
                if (!thread.getState().equals(Thread.State.RUNNABLE)) {
    
    
                    LockSupport.unpark(requestQueue.peek());
                }
            }
        }
    }

Of course, it’s not difficult to borrow and borrow again. The main consideration here is whether the thread in the current queue returns the token and the state of the thread. The main reason is to wake up and don’t wake up again. Of course, this place It is only considered that it will not wake up if it is awakened, and the other state of the thread has not been considered
PS: It is not fair here, but it has not been realized. The main thing is that it is painful to not be awakened! Please don’t hesitate to enlighten me if you see it! ! !

Guess you like

Origin blog.csdn.net/cj181jie/article/details/108734434