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

NO IMAGE

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

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

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;
}

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

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給大家看看使用情況。

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

讀寫鎖是為了更大的增加線程的執行效率的。上面介紹的鎖無論是讀還是寫都會進入到對應的拿鎖階段,而這個時候讀寫鎖就很好的體現了它的作用。它進行功能上面的劃分,使得讀寫分開進行。

讀鎖與寫鎖之間關聯:

非阻塞阻塞
阻塞阻塞

看下一個小的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中兩種鎖的操作方式以及他們的特點,具體在業務中的使用還是得需要看具體的需求,考慮是否有必要去使用。

相關文章

JAVA操作碼相關指令介紹

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

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

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