上篇文章中讲到了重入锁以及对应的条件操做,详情见JAVA并发之多线程基础(2)。这篇文章咱们就继续谈JDK中含有的并发操做类。java
对于大部分的锁来讲,线程之间的都是互斥的,排他的,只容许一个线程进入临界区中来。可是信号量这里容许多个线程进入临界区。能够广义上面看作是一个共享锁。多线程
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);//拿取多个信号量许可
}
复制代码
release()
方法是释放当前线程的信号量。public void release() {
sync.releaseShared(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);
}
}
}
复制代码
读写锁是为了更大的增长线程的执行效率的。上面介绍的锁不管是读仍是写都会进入到对应的拿锁阶段,而这个时候读写锁就很好的体现了它的做用。它进行功能上面的划分,使得读写分开进行。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