Sike Semaphore synchronization java source parsing Series

problem

What (1) Semaphore that?

(2) Semaphore What features?

(3) Semaphore often used in what scenario?

Whether the license number (4) Semaphore can be dynamically increased or decreased?

How (5) Semaphore for current limiting?

Brief introduction

Semaphore, Semaphore, which holds a number of licenses (permits), each call to acquire () will consume a license, each call to release () will return a license.

characteristic

Semaphore commonly used to limit the number of times the same time access to shared resources, is often said that the current limit.

Here we learn together how Semaphore is implemented in Java.

Class structure

Semaphore

Contains a Semaphore achieved AQS synchronizer Sync, and its two subclasses FairSync and NonFairSync, this distinction is explained Semaphore fair and unfair mode mode.

Source code analysis

For ReentrantLock and ReentrantReadWriteLock based analysis before, this article is relatively simple, some methods previously talked about the direct skip, are interested can be pulled before the bottom of the article to view the article.

Sync inner class

// java.util.concurrent.Semaphore.Sync
abstract static class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 1192457210091910933L;
    // 构造方法,传入许可次数,放入state中
    Sync(int permits) {
        setState(permits);
    }
    // 获取许可次数
    final int getPermits() {
        return getState();
    }
    // 非公平模式尝试获取许可
    final int nonfairTryAcquireShared(int acquires) {
        for (;;) {
            // 看看还有几个许可
            int available = getState();
            // 减去这次需要获取的许可还剩下几个许可
            int remaining = available - acquires;
            // 如果剩余许可小于0了则直接返回
            // 如果剩余许可不小于0,则尝试原子更新state的值,成功了返回剩余许可
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                return remaining;
        }
    }
    // 释放许可
    protected final boolean tryReleaseShared(int releases) {
        for (;;) {
            // 看看还有几个许可
            int current = getState();
            // 加上这次释放的许可
            int next = current + releases;
            // 检测溢出
            if (next < current) // overflow
                throw new Error("Maximum permit count exceeded");
            // 如果原子更新state的值成功,就说明释放许可成功,则返回true
            if (compareAndSetState(current, next))
                return true;
        }
    }
    // 减少许可
    final void reducePermits(int reductions) {
        for (;;) {
            // 看看还有几个许可
            int current = getState();
            // 减去将要减少的许可
            int next = current - reductions;
            // 检测举出
            if (next > current) // underflow
                throw new Error("Permit count underflow");
            // 原子更新state的值,成功了返回true
            if (compareAndSetState(current, next))
                return;
        }
    }
    // 销毁许可
    final int drainPermits() {
        for (;;) {
            // 看看还有几个许可
            int current = getState();
            // 如果为0,直接返回
            // 如果不为0,把state原子更新为0
            if (current == 0 || compareAndSetState(current, 0))
                return current;
        }
    }
}

Sync by several methods to achieve, we get the following information:

(1) License is passed in the construction method;

(2) The license is stored in the state variable state;

(3) when attempting to acquire a license, the state value minus 1;

(4) the time when the state value is 0, it can no longer be licensed;

(5) when the release of a license, the state added to the value 1;

(6) the number of licenses can be changed dynamically;

Internal class NonfairSync

// java.util.concurrent.Semaphore.NonfairSync
static final class NonfairSync extends Sync {
    private static final long serialVersionUID = -2694183684443567898L;
    // 构造方法,调用父类的构造方法
    NonfairSync(int permits) {
        super(permits);
    }
    // 尝试获取许可,调用父类的nonfairTryAcquireShared()方法
    protected int tryAcquireShared(int acquires) {
        return nonfairTryAcquireShared(acquires);
    }
}

Non-equity modes, direct call nonfairTryAcquireShared parent class () attempts to obtain a license.

Internal class FairSync

// java.util.concurrent.Semaphore.FairSync
static final class FairSync extends Sync {
    private static final long serialVersionUID = 2014338818796000944L;
    // 构造方法,调用父类的构造方法
    FairSync(int permits) {
        super(permits);
    }
    // 尝试获取许可
    protected int tryAcquireShared(int acquires) {
        for (;;) {
            // 公平模式需要检测是否前面有排队的
            // 如果有排队的直接返回失败
            if (hasQueuedPredecessors())
                return -1;
            // 没有排队的再尝试更新state的值
            int available = getState();
            int remaining = available - acquires;
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                return remaining;
        }
    }
}

Fair mode, check to make sure the front of the queue, the queue if there is a failure to obtain permission to enter the queue line up, or the attempt to update the state of atomic values.

Construction method

// 构造方法,创建时要传入许可次数,默认使用非公平模式
public Semaphore(int permits) {
    sync = new NonfairSync(permits);
}
// 构造方法,需要传入许可次数,及是否公平模式
public Semaphore(int permits, boolean fair) {
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

You need to pass the license number when you create a Semaphore.

Semaphore default mode is unfair, but you can call the second constructor stated as being fair mode.

The following methods are relatively simple in front of the contents studied opinion, Tong brother just to name some of the features supported by the Semaphore.

The following methods are described with respect to non-equity modes.

acquire () method

public void acquire() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

Obtaining a license, using the default may interrupt, if the attempt fails obtain a license, AQS will enter the queue line.

acquireUninterruptibly () method

public void acquireUninterruptibly() {
    sync.acquireShared(1);
}

Obtaining a license, non-disruptive way, if you try to obtain a license fails, AQS will enter the queue line.

tryAcquire () method

public boolean tryAcquire() {
    return sync.nonfairTryAcquireShared(1) >= 0;
}

Try to obtain a license to use non-equity modes Sync method attempts to obtain a license, regardless of whether or not to obtain permission to return with only one try, will not enter the queue line.

tryAcquire(long timeout, TimeUnit unit)方法

public boolean tryAcquire(long timeout, TimeUnit unit)
    throws InterruptedException {
    return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}

Try to obtain a license, the first attempt to obtain a license, if that fails it will wait for the timeout time, this time did not get the license, false is returned, true otherwise;

release () method

public void release() {
    sync.releaseShared(1);
}

Releases a permit, a license is released when the state will increase the value of 1, and the next will wake up a waiting thread gets permit.

acquire (int permits) Method

public void acquire(int permits) throws InterruptedException {
    if (permits < 0) throw new IllegalArgumentException();
    sync.acquireSharedInterruptibly(permits);
}

Fetching more than one license, you can interrupt.

acquireUninterruptibly(int permits)方法

public void acquireUninterruptibly(int permits) {
    if (permits < 0) throw new IllegalArgumentException();
    sync.acquireShared(permits);
}

Fetching more than one license, non-disruptive way.

tryAcquire (int permits) Method

public boolean tryAcquire(int permits) {
    if (permits < 0) throw new IllegalArgumentException();
    return sync.nonfairTryAcquireShared(permits) >= 0;
}

Attempt to obtain more than one license, try only once.

tryAcquire(int permits, long timeout, TimeUnit unit)方法

public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
    throws InterruptedException {
    if (permits < 0) throw new IllegalArgumentException();
    return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
}

Try to obtain more than one license, and will wait for the timeout time, this time did not get permission to return false, true otherwise.

release(int permits)方法

public void release(int permits) {
    if (permits < 0) throw new IllegalArgumentException();
    sync.releaseShared(permits);
}

A release multiple licenses, the value of the state will increase the number of permits.

availablePermits()方法

public int availablePermits() {
    return sync.getPermits();
}

Gets the number of licenses available.

drainPermits()方法

public int drainPermits() {
    return sync.drainPermits();
}

The destruction of the number of licenses currently available, there is no impact on the license has been obtained, the current remaining license will be destroyed.

reducePermits(int reduction)方法

protected void reducePermits(int reduction) {
    if (reduction < 0) throw new IllegalArgumentException();
    sync.reducePermits(reduction);
}

Reduce the number of licenses.

to sum up

(1) Semaphore, also known as semaphores, typically used to control the same time on the access to shared resources, that is, limiting the scene;

(2) internal Semaphore implementation is based on a shared lock AQS be achieved;

(3) Semaphore initialization of the need to specify the license number, the license number is stored in the state;

(4) When acquiring a license, the state value minus 1;

(5) the release of a license, the state value by 1;

(6) n licenses may be dynamically reduced;

(7) can dynamically increase n licenses do?

Egg

(1) How to dynamically increase n licenses?

A: Call release (int permits) can be. We know that the release license when the value of the state will increase accordingly, and then look at the source code release license, find and release the lock ReentrantLock a little difference, Semaphore release license when checking the current thread does not have permission had not acquired, so you can call free license to add some dynamic methods license.

(2) how to achieve current limit?

A: The current limiting, that a sudden increase in the flow of time, to be able to upper limits on sudden large flow impact on downstream services, in a distributed system limiting generally done at the gateway layer, of course, the individual can own functions simply to limit the flow, such as spike scene, if only 10 commodities need to spike, then the service itself can be restricted while only 100 requests come in, set aside all other requests, such services would not stress too much.

Semaphore can directly use for this feature to limit the flow, the following is the code to achieve:

public class SemaphoreTest {
    public static final Semaphore SEMAPHORE = new Semaphore(100);
    public static final AtomicInteger failCount = new AtomicInteger(0);
    public static final AtomicInteger successCount = new AtomicInteger(0);

    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            new Thread(()->seckill()).start();
        }
    }

    public static boolean seckill() {
        if (!SEMAPHORE.tryAcquire()) {
            System.out.println("no permits, count="+failCount.incrementAndGet());
            return false;
        }

        try {
            // 处理业务逻辑
            Thread.sleep(2000);
            System.out.println("seckill success, count="+successCount.incrementAndGet());
        } catch (InterruptedException e) {
            // todo 处理异常
            e.printStackTrace();
        } finally {
            SEMAPHORE.release();
        }
        return true;
    }
}

Recommended Reading

1, Sike java synchronization of the Opening Series

2, Sike Unsafe java class of analytic magic

3, Sike java synchronized series of JMM (Java Memory Model)

4, Sike java synchronized series of volatile resolve

5, Sike java synchronized series of synchronized resolve

6, Sike java series of synchronous write himself a lock Lock

7, Sike java synchronized series of articles from the AQS

8, Sike ReentrantLock resolve java source code synchronized series of (a) - fair locks, lock unfair

9, Sike ReentrantLock resolve java source code synchronized series of (two) - Conditions Lock

10, Sike java synchronized series of ReentrantLock VS synchronized

11, Sike ReentrantReadWriteLock parse java source synchronous series

I welcome the attention of the public number "Tong brother read source" view source code more series, and brother Tong source of ocean swim together.

qrcode

Guess you like

Origin www.cnblogs.com/tong-yuan/p/Semaphore.html
Recommended