Semaphore Semaphore principle of concurrent java

1. Introduction semaphore Semaphore

We operate a car park an example to illustrate the role of the semaphore. Assuming that only three parking spaces, beginning three parking spaces are empty. Then if at the same time to the three vehicles, which allowed them to enter the janitor to enter, and then lower the car stopped. Later, at the entrance of the car must wait until the vehicle has left the parking lot. At this time, if there is a car leaving the parking lot after the janitor that, open the car stopped, put one, if they leave one, then they can be put into one, and so forth.

In this system, parking lot, parking is a public resource, each car is like a thread, the doorman is the role played by semaphore. Semaphore is a non-negative integer, indicates the currently available number (parking spaces analog signal the amount of the above example can be idle) public resources, when a thread is to use common resources (in the above example can be used vehicle analogy thread), we must first see the semaphore if the semaphore value is greater than 1, it is decremented by 1, and then to occupy public resources. If the semaphore is 0, the thread will own blocked until another thread releases public resources.

On the semaphore We define two operations: acquire (get) and release (release). When a thread calls acquire the operation, it successfully acquired either through a semaphore (signal minus 1), or keep on waiting until the thread releases the semaphore, or timeout. release (release) will actually semaphore value plus 1, and then wake up waiting threads.

The main purpose for two semaphore, a mutex is a plurality of shared resources, for controlling a number of other concurrent threads.


2. source code analysis of the semaphore Semaphore

In Java and contracting in, Semaphore class represents the amount of signal. Semaphore mainly through internal management AQS (AbstractQueuedSynchronizer) to implement threads. Semaphore has two constructors, the parameter indicates the number of licenses permits , it is finally passed to the state of the AQS value. Thread running first obtain a license, if successful, would reduce the number of license 1 , thread running, when the end of the thread running on the release of the license, the license number is incremented . If the license number is 0, the acquisition fails, the thread located in the waiting queue AQS, it will wake up other threads release license. You can also specify its fairness when creating Semaphore object. The amount of signal commonly used unfair, unfair semaphore means getting permission first try to obtain a license without having to be concerned about whether there need to obtain permission thread located in the waiting queue, if the acquisition fails, will the column. And fair amount signal when obtaining the license must first wait to see whether a thread already in the queue, if there is into the column.

Constructor

//非公平的构造函数
public Semaphore(int permits) {
    sync = new NonfairSync(permits);
}

//通过fair参数决定公平性
public Semaphore(int permits, boolean fair) {
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
} 复制代码

acquire the source code

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

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

final int nonfairTryAcquireShared(int acquires) {
    for (;;) {
        int available = getState();
        int remaining = available - acquires; //剩余许可数
        if (remaining < 0 ||
            compareAndSetState(available, remaining)) 
            return remaining;
    }
}复制代码

As can be seen, if the remaining <0 i.e. after obtaining the license, the license number is less than 0, then the acquisition has failed, the thread will be blocked in doAcquireSharedInterruptibly process itself, and then into the column.

release source code

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

public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}

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");
        if (compareAndSetState(current, next))
            return true;
    }
}复制代码

To release the license is to be seen in the state of AQS value plus 1. And waking up first node queue by doReleaseShared. Semaphore can be seen using the AQS sharing mode, waiting in the queue first node, if the first node is successfully obtain a license, a node will wake up the next, and so on.

3. Example of use

package javalearning;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
	private Semaphore smp = new Semaphore(3); 
	private Random rnd = new Random();
	
	class TaskDemo implements Runnable{
		private String id;
		TaskDemo(String id){
			this.id = id;
		}
		@Override
		public void run(){
			try {
				smp.acquire();
				System.out.println("Thread " + id + " is working");
				Thread.sleep(rnd.nextInt(1000));
				smp.release();
				System.out.println("Thread " + id + " is over");
			} catch (InterruptedException e) {
			}
		}
	}
	
	public static void main(String[] args){
		SemaphoreDemo semaphoreDemo = new SemaphoreDemo();
		//注意我创建的线程池类型,
		ExecutorService se = Executors.newCachedThreadPool();
		se.submit(semaphoreDemo.new TaskDemo("a"));
		se.submit(semaphoreDemo.new TaskDemo("b"));
		se.submit(semaphoreDemo.new TaskDemo("c"));
		se.submit(semaphoreDemo.new TaskDemo("d"));
		se.submit(semaphoreDemo.new TaskDemo("e"));
		se.submit(semaphoreDemo.new TaskDemo("f"));
		se.shutdown();
	}
}

运行结果Thread c is workingThread b is workingThread a is workingThread c is overThread d is workingThread b is overThread e is workingThread a is overThread f is workingThread d is overThread e is overThread f is over
复制代码


Reproduced in: https: //juejin.im/post/5cf7624cf265da1b7c610705

Guess you like

Origin blog.csdn.net/weixin_34168880/article/details/91427196