JAVA併發之多線程基礎(3)

上篇文章中講到了重入鎖以及對應的條件操做,詳情見JAVA併發之多線程基礎(2)。這篇文章咱們就繼續談JDK中含有的併發操做類。java

Semaphore

對於大部分的鎖來講,線程之間的都是互斥的,排他的,只容許一個線程進入臨界區中來。可是信號量這裏容許多個線程進入臨界區。能夠廣義上面看作是一個共享鎖。多線程

  1. acquire()這個是去拿一個信號量,使得該線程能夠進入到臨界區。
public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);//是去拿去一個信號量許可
    }
複製代碼

同時一個線程也能夠去拿去多個信號量。併發

public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);//拿取多個信號量許可
    }
複製代碼
  1. release()方法是釋放當前線程的信號量。
public void release() {
        sync.releaseShared(1);
    }
複製代碼
  1. tryAcquire()是嘗試獲取信號量,獲取不到就去作其餘的事情。
public boolean tryAcquire() {
        return sync.nonfairTryAcquireShared(1) >= 0;
    }
複製代碼

同時它也有根據時間嘗試獲取信號量的方法:ide

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

固然,信號量自身裏面也有公平信號和非公平信號,裏面使用到的也是AQS。JDK下面的併發操做類中最主要的核心也就是AQS。下面有個小的Demo給你們看看使用狀況。post

package com.montos.lock;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/** * 信號量 * * @author Montos * * 2019年5月30日 * */
public class SemaphoreDemo implements Runnable {
	final Semaphore semaphore = new Semaphore(5);

	@Override
	public void run() {
		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);
		}
	}
}
複製代碼

ReadWriteLock

讀寫鎖是爲了更大的增長線程的執行效率的。上面介紹的鎖不管是讀仍是寫都會進入到對應的拿鎖階段,而這個時候讀寫鎖就很好的體現了它的做用。它進行功能上面的劃分,使得讀寫分開進行。ui

讀鎖與寫鎖之間關聯:spa

非阻塞 阻塞
阻塞 阻塞

看下一個小的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) {
		// 同時讀、寫
		ExecutorService service = Executors.newCachedThreadPool();
		service.execute(new Runnable() {
			@Override
			public void run() {
				readFile(Thread.currentThread());
			}
		});
		service.execute(new Runnable() {
			@Override
			public void run() {
				writeFile(Thread.currentThread());
			}
		});
	}
	// 讀操做
	public static void readFile(Thread thread) {
		lock.readLock().lock();
		boolean readLock = lock.isWriteLocked();
		if (!readLock) {
			System.out.println("當前爲讀鎖!");
		}
		try {
			for (int i = 0; i < 5; i++) {
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(thread.getName() + ":正在進行讀操做……");
			}
			System.out.println(thread.getName() + ":讀操做完畢!");
		} finally {
			System.out.println("釋放讀鎖!");
			lock.readLock().unlock();
		}
	}
	// 寫操做
	public static void writeFile(Thread thread) {
		lock.writeLock().lock();
		boolean writeLock = lock.isWriteLocked();
		if (writeLock) {
			System.out.println("當前爲寫鎖!");
		}
		try {
			for (int i = 0; i < 5; i++) {
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(thread.getName() + ":正在進行寫操做……");
			}
			System.out.println(thread.getName() + ":寫操做完畢!");
		} finally {
			System.out.println("釋放寫鎖!");
			lock.writeLock().unlock();
		}
	}
}
複製代碼

以上介紹的是JDK中兩種鎖的操做方式以及他們的特色,具體在業務中的使用仍是得須要看具體的需求,考慮是否有必要去使用。3d

相關文章
相關標籤/搜索