While previous articles covered reentrant and read-write locks (see link at the end of this article), this article will focus on the Java and packet sending tool class Semaphore (Semaphore).

Semaphore characteristics

  1. Is a shared lock (similar to read lock in read/write lock)
  2. AQS based implementation (AQS related content can refer to the link at the end of the article)
  3. Allow a certain number of threads to acquire the lock

Semaphore example

Semaphore can be used to restrict access to a resource by a certain number of threads. Here is an example of what this means.

public static void main(String[] args) { DateFormat df = new SimpleDateFormat("HH:mm:ss---"); Semaphore semaphore = new Semaphore(3); Runnable runnable = new Runnable() { @Override public void run() { try { semaphore.acquire(); System.out.println(df.format(new Date()) + Thread.currentThread().getName() + " got resource"); Thread.sleep(2000); } catch (Exception e) { e.printStackTrace(); } finally { semaphore.release(); }}}; for (int i = 0; i < 9; i++) { new Thread(runnable, "Thread" + i).start(); }}Copy the code

In the example above, we created a semaphore with a limit of 3 and started 9 threads to execute their respective tasks (all of which were asleep for 2 seconds). As we can see from the print below, only 3 threads were able to acquire the semaphore and execute it at the same time.

11:12:29---Thread1 got resource
11:12:29---Thread3 got resource
11:12:29---Thread0 got resource
11:12:31---Thread4 got resource
11:12:31---Thread2 got resource
11:12:31---Thread6 got resource
11:12:33---Thread5 got resource
11:12:33---Thread7 got resource
11:12:33---Thread8 got resource
Copy the code

Semaphore principle

Semaphore contains a Sync object that inherits AQS, and Sync object has two subclasses NonfaireSync and FairSync, so Semaphore also supports fair and unfair locking.

Also, fair and unfair locks are reflected in Semaphore’s constructor:

Public Semaphore(int permitting) {sync = new NonfairSync(permitting); Public Semaphore(int permits, Boolean fair) {sync = fair? new FairSync(permits) : new NonfairSync(permits); }Copy the code

The Semaphore lock can be obtained as follows. There are two main methods:

public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
}
Copy the code

TryAcquireShared: Attempts to acquire the lock, returns positive or 0 on success, negative on failure.

There are different implementation logic for fair and unfair locks:

Fair lock: before thread check if there are threads queuing inside the AQS, then return -1, enter the AQS queuing; Otherwise, the thread will compete with other threads to obtain the lock. If the competition succeeds, the thread will get the lock and return. If the competition fails, the thread will enter the AQS queue.

protected int tryAcquireShared(int acquires) { for (;;) { if (hasQueuedPredecessors()) return -1; Permitting = permitting int available = getState(); permitting = permitting int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; }}Copy the code

Unfair lock: the current thread directly participates in the competition to obtain the lock. If the competition succeeds, the thread will get the lock and return. If the competition fails, the thread will enter the AQS queue (regardless of whether the AQS has other threads queuing).

final int nonfairTryAcquireShared(int acquires) { for (;;) { int available = getState(); int remaining = available - acquires; if (remaining < 0 || compareAndSetState(available, remaining)) return remaining; }}Copy the code

DoAcquireSharedInterruptibly: similar to read lock calls doAcquireShared method, if the current thread for the lock, fire up its subsequent nodes in AQS, otherwise enter AQS queue.

Releasing Semaphore locks is relatively simple. Fair locks and unfair locks have the same logic:

Increment state by 1 and wake up other threads queuing at AQS.

Demo code location


SRC/main/Java/net/weichitech/juc/SemaphoreTest. Java, small western/Java programming – learning – Gitee.com

Related articles

JAVA concurrency ReentrantLock principle analysis

JAVA Concurrency: ReentrantReadWriteLock

JAVA Concurrency ReentrantReadWriteLock (2)