The previous article covered reentrant locking and the corresponding conditional operations, as described in The Multithreaded Basics of JAVA Concurrency (2). In this article we continue to talk about the concurrency classes included in the JDK.

Semaphore

For most locks, threads are mutually exclusive, allowing only one thread to enter a critical section. But the semaphore here allows multiple threads to enter the critical section. It can be viewed broadly as a shared lock.

  1. acquire()This is to take a semaphore so that the thread can enter the critical section.
public void acquire(a) throws InterruptedException {
        sync.acquireSharedInterruptibly(1);// To get a semaphore license
    }
Copy the code

A thread can also take more than one semaphore.

public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);// Get multiple semaphore permissions
    }
Copy the code
  1. release()The method is to release the semaphore of the current thread.
public void release(a) {
        sync.releaseShared(1);
    }
Copy the code
  1. tryAcquire()It’s trying to get a semaphore, failing that, doing something else.
public boolean tryAcquire(a) {
        return sync.nonfairTryAcquireShared(1) > =0;
    }
Copy the code

It also has a way of trying to get semaphores based on time:

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

Of course, there are also fair and unfair signals in the semaphore itself, and AQS are also used in it. The main core of the concurrent operation class in the JDK is AQS. Here’s a little Demo to show you how it works.

package com.montos.lock;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/** ** Semaphore **@authorMontos * * May 30, 2019 * */
public class SemaphoreDemo implements Runnable {
	final Semaphore semaphore = new Semaphore(5);

	@Override
	public void run(a) {
		try {
			semaphore.acquire();
			Thread.sleep(2000);
			System.out.println(Thread.currentThread().getId() + " thread is done");
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally{ semaphore.release(); }}public static void main(String[] args) {
		ExecutorService exec = Executors.newFixedThreadPool(20);
		final SemaphoreDemo demo = new SemaphoreDemo();
		for (int i = 0; i < 20; i++) { exec.submit(demo); }}}Copy the code

ReadWriteLock

Read/write locks are used to increase thread efficiency. The lock introduced above will enter the corresponding lock holding stage whether it is read or write, and this time the read and write lock is a good embodiment of its role. It divides functions so that reads and writes are separated.

The association between read locks and write locks:

read write
read non-blocking blocking
write blocking blocking

Take a look at the next small demo:

package com.montos.lock;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadLockDemo {

	public static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

	public static void main(String[] args) {
		// Read and write simultaneously
		ExecutorService service = Executors.newCachedThreadPool();
		service.execute(new Runnable() {
			@Override
			public void run(a) { readFile(Thread.currentThread()); }}); service.execute(new Runnable() {
			@Override
			public void run(a) { writeFile(Thread.currentThread()); }}); }/ / read operation
	public static void readFile(Thread thread) {
		lock.readLock().lock();
		boolean readLock = lock.isWriteLocked();
		if(! readLock) { System.out.println("Currently a read lock!");
		}
		try {
			for (int i = 0; i < 5; i++) {
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(thread.getName() + ": Reading operation in progress......");
			}
			System.out.println(thread.getName() + ": Read operation complete!");
		} finally {
			System.out.println("Release read lock!"); lock.readLock().unlock(); }}/ / write operations
	public static void writeFile(Thread thread) {
		lock.writeLock().lock();
		boolean writeLock = lock.isWriteLocked();
		if (writeLock) {
			System.out.println("Currently write lock!");
		}
		try {
			for (int i = 0; i < 5; i++) {
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(thread.getName() + ": Write operation in progress......");
			}
			System.out.println(thread.getName() + ": Write operation complete!");
		} finally {
			System.out.println("Release write lock!"); lock.writeLock().unlock(); }}}Copy the code

The above is the introduction of the JDK in the operation of two locks and their characteristics, the specific use of business or depends on the specific requirements, consider whether it is necessary to use.