锁 - 抽象锁AbstractQueuedSynchronizer
抽象锁
AbstractQueuedSynchronizer 很难去翻译这个词,抽象排队同步器?这里姑且叫抽象锁吧。
抽象锁只是一个抽象类,锁封装了一些锁的常规操作,包括信号量、倒数锁、可重入锁,内部代码都包含了抽象同步锁的实现类。
抽象同步锁用到了Unsafe类,Unsafe虽然在Java的基础包中,但是常规编程中根本无法调用。所以,目前阶段,可以将抽象同步锁看做是最底层的代码。
使用方式
在使用过程中会发现,IDE不会给任何提示,似乎没有任何抽象方法需要实现。
抽象同步锁确实不包含任何抽象函数,但是包含许多空函数,它希望开发人员有选择地,去重写这些函数。
比如,你希望锁调用acquireSharedInterruptibly()函数,那么就需要重写tryAcquireShared()函数,具体对应关系如下:
acquireSharedInterruptibly() —— tryAcquireShared()
acquireShared() —— tryAcquireShared()
releaseShared() —— tryReleaseShared()
acquireInterruptibly() —— tryAcquire()
acquire() —— tryAcquire()
release() —— tryRelease()
独占和共享
此类支持默认的 “独占模式” 和 “共享模式” 之一,或者二者都支持。
独占模式就像代码中的同步块,被 synchronized 修饰的函数,只有一个线程可以访问,其他线程试图获取该锁将无法取得成功;
而共享模式则用在一些共享数据上,就像阻塞队列,多个线程同时获取锁,多个线程都可能访问成功。
以文件读写锁为例:读取时,允许多个线程同时读,这是共享的;而写入的时候,只允许一个线程写,这时候就是独占的。
使用抽象同步锁实现线程同步(共享模式)
多个子线程先执行,然后主线程运行
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import com.sea.common.util.RandomUtils;
/**
* 抽象锁的实现类一般设计为静态内部类,这里直接调用实现类,展示其功能
* 我的需求明确,想要一个共享模式的锁,因此只实现tryAcquireShared()和tryReleaseShared()函数
*
* @author ChenSS on 2018年2月3日
*/
class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -860558119172333780L;
Sync(int count) {
setState(count);
}
/**
* 此方法应该查询是否允许它在共享模式下获取对象状态
*/
@Override
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
/**
* 同倒计时锁功能类似,每次释放锁,锁的总量减一
*/
@Override
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c - 1;
if (super.compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
int count = 5;
Sync sync = new Sync(count);
while (count-- > 0) {
final int n = count;
new Thread(() -> {
try {
Thread.sleep(3000 + RandomUtils.nextLong(3000));
System.out.println("完成第" + n +"个初始化");
sync.releaseShared(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
sync.acquireShared(count);
System.out.println("ok");
}
}
官方Demo(独占模式)
收录于 jdk 文档内的案例
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
class Mutex implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7189538917731084955L;
private static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 8005382235859105335L;
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
@Override
public boolean tryAcquire(int acquires) {
assert acquires == 1; // Otherwise unused
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override
protected boolean tryRelease(int releases) {
assert releases == 1; // Otherwise unused
if (getState() == 0)
throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public Condition newCondition() {
return new ConditionObject();
}
}
private final Sync sync = new Sync();
@Override
public void lock() {
sync.acquire(1);
}
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
@Override
public void unlock() {
sync.release(1);
}
@Override
public Condition newCondition() {
return sync.newCondition();
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
@Override
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public boolean isLocked() {
return sync.isHeldExclusively();
}
public boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
}
public class Test {
private final Mutex lock = new Mutex();
/**
* 多线程同时访问,每次只有一个函数执行
*/
public void printLine() {
final Mutex l = lock;
l.lock();
try {
Thread.sleep(1000);
System.out.println("-----------------------");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
int count = 5;
Test test = new Test();
while (count-- > 0) {
new Thread(() -> {
test.printLine();
}).start();
}
}
}
疯狂的妞妞 :每一天,做什么都好,不要什么都不做!