共计 7380 个字符,预计需要花费 19 分钟才能阅读完成。
序言
上一节咱们学习了异步查问转同步的 7 种实现形式,明天咱们就来学习一下,如何对其进行封装,使其成为一个更加便于应用的工具。
思维导图如下:
拓展浏览
java 手写并发框架(1)异步查问转同步的 7 种实现形式
异步转同步的便利性
实现形式
- 循环期待
- wait & notify
- 应用条件锁
- 应用 CountDownLatch
- 应用 CyclicBarrier
- Future
- Spring EventListener
上一节咱们曾经对下面的 7 种实现形式进行了具体的介绍,没有看过的同学能够去简略回顾一下。
然而这样集体感觉还是不够不便,懈怠是提高的阶梯。
更进一步简化
咱们心愿达到上面的成果:
@Sync
public String queryId() {System.out.println("开始查问");
return id;
}
@SyncCallback(value = "queryId")
public void queryIdCallback() {System.out.println("回调函数执行");
id = "123";
}
通过注解间接须要同步的办法,和回调的办法,代码中间接调用即可。
咱们首先实现基于字节码加强的版本,后续将实现整合 spring, springboot 的版本。
锁的代码实现
锁的定义
咱们将原来的实现形象为加锁和解锁,为了便于拓展,接口定义如下:
package com.github.houbb.sync.api.api;
/**
* @author binbin.hou
* @since 0.0.1
*/
public interface ISyncLock {
/**
* 期待策略
* @param context 上下文
* @since 0.0.1
*/
void lock(final ISyncLockContext context);
/**
* 解锁策略
* @param context 上下文
* @since 0.0.1
*/
void unlock(final ISyncUnlockContext context);
}
其中上下文加锁和解锁做了辨别,不过临时内容是一样的。
次要是超时工夫和单位:
package com.github.houbb.sync.api.api;
import java.util.concurrent.TimeUnit;
/**
* @author binbin.hou
* @since 0.0.1
*/
public interface ISyncLockContext {
/**
* 超时工夫
* @return 后果
*/
long timeout();
/**
* 超时工夫单位
* @return 后果
*/
TimeUnit timeUnit();}
锁策略实现
咱们本节次要实现下上一节中的几种锁实现。
目前咱们抉择其中的是个进行实现:
wait & notify
package com.github.houbb.sync.core.support.lock;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import com.github.houbb.sync.api.api.ISyncLock;
import com.github.houbb.sync.api.api.ISyncLockContext;
import com.github.houbb.sync.api.api.ISyncUnlockContext;
import com.github.houbb.sync.api.exception.SyncRuntimeException;
/**
* 期待告诉同步
*
* @author binbin.hou
* @since 0.0.1
*/
public class WaitNotifyLock implements ISyncLock {private static final Log log = LogFactory.getLog(WaitNotifyLock.class);
/**
* 申明对象
*/
private final Object lock = new Object();
@Override
public synchronized void lock(ISyncLockContext context) {synchronized (lock) {
try {long timeoutMills = context.timeUnit().toMillis(context.timeout());
log.info("进入期待,超时工夫为:{}ms", timeoutMills);
lock.wait(timeoutMills);
} catch (InterruptedException e) {log.error("中断异样", e);
throw new SyncRuntimeException(e);
}
}
}
@Override
public void unlock(ISyncUnlockContext context) {synchronized (lock) {log.info("唤醒所有期待线程");
lock.notifyAll();}
}
}
加锁的局部比较简单,咱们从上下文中获取超时工夫和超时单位,间接和上一节内容相似,调用即可。
至于上下文中的信息是怎么来的,咱们后续就会解说。
条件锁实现
这个在有了上一节的根底之后也非常简单。
外围流程:
(1)创立锁
(2)获取锁的 condition
(3)执行加锁和解锁
package com.github.houbb.sync.core.support.lock;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import com.github.houbb.sync.api.api.ISyncLock;
import com.github.houbb.sync.api.api.ISyncLockContext;
import com.github.houbb.sync.api.api.ISyncUnlockContext;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 期待告诉同步
*
* @author binbin.hou
* @since 0.0.1
*/
public class LockConditionLock implements ISyncLock {private static final Log log = LogFactory.getLog(LockConditionLock.class);
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
@Override
public synchronized void lock(ISyncLockContext context) {lock.lock();
try{log.info("程序进入锁定状态");
condition.await(context.timeout(), context.timeUnit());
} catch (InterruptedException e) {log.error("程序锁定状态异样", e);
} finally {lock.unlock();
}
}
@Override
public void unlock(ISyncUnlockContext context) {lock.lock();
try{log.info("解锁状态,唤醒所有期待线程。");
condition.signalAll();} finally {lock.unlock();
}
}
}
CountDownLatch 实现
package com.github.houbb.sync.core.support.lock;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import com.github.houbb.sync.api.api.ISyncLock;
import com.github.houbb.sync.api.api.ISyncLockContext;
import com.github.houbb.sync.api.api.ISyncUnlockContext;
import java.util.concurrent.CountDownLatch;
/**
* 期待告诉同步
*
* @author binbin.hou
* @since 0.0.1
*/
public class CountDownLatchLock implements ISyncLock {private static final Log log = LogFactory.getLog(CountDownLatchLock.class);
/**
* 闭锁
* 调用 1 次,后续办法即可通行。*/
private CountDownLatch countDownLatch = new CountDownLatch(1);
@Override
public synchronized void lock(ISyncLockContext context) {countDownLatch = new CountDownLatch(1);
try {log.info("进入期待,超时工夫为:{},超时单位:{}", context.timeout(),
context.timeUnit());
boolean result = countDownLatch.await(context.timeout(), context.timeUnit());
log.info("期待后果: {}", result);
} catch (InterruptedException e) {log.error("锁中断异样", e);
}
}
@Override
public void unlock(ISyncUnlockContext context) {log.info("执行 unlock 操作");
countDownLatch.countDown();}
}
留神:这里为了保障 countDownLatch 能够屡次应用,咱们在每一次加锁的时候,都会从新创立 CountDownLatch。
CyclicBarrierLock 锁实现
package com.github.houbb.sync.core.support.lock;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import com.github.houbb.sync.api.api.ISyncLock;
import com.github.houbb.sync.api.api.ISyncLockContext;
import com.github.houbb.sync.api.api.ISyncUnlockContext;
import com.github.houbb.sync.api.exception.SyncRuntimeException;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeoutException;
/**
* @author binbin.hou
* @since 0.0.1
*/
public class CyclicBarrierLock implements ISyncLock {private static final Log log = LogFactory.getLog(CyclicBarrierLock.class);
private final CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
@Override
public synchronized void lock(ISyncLockContext context) {
try {log.info("进入锁定状态, timeout:{}, timeunit: {}",
context.timeout(), context.timeUnit());
cyclicBarrier.await(context.timeout(), context.timeUnit());
log.info("重置 cyclicBarrier");
cyclicBarrier.reset();} catch (InterruptedException | BrokenBarrierException | TimeoutException e) {log.error("锁定时遇到异样", e);
throw new SyncRuntimeException(e);
}
}
@Override
public void unlock(ISyncUnlockContext context) {
try {log.info("解锁信息");
cyclicBarrier.await(context.timeout(), context.timeUnit());
} catch (InterruptedException | TimeoutException | BrokenBarrierException e) {log.error("解锁时遇到异样", e);
}
}
}
这里和 CountDownLatchLock 的实现十分相似,不过 CyclicBarrier 有一个益处,就是能够复用。
咱们在每一次解锁之后,重置一下栅栏:
log.info("重置 cyclicBarrier");
cyclicBarrier.reset();
锁的工具类
为了简略的生成上述几种锁的实例,咱们提供了一个简略的工具类办法:
package com.github.houbb.sync.core.support.lock;
import com.github.houbb.heaven.support.instance.impl.Instances;
import com.github.houbb.sync.api.api.ISyncLock;
import com.github.houbb.sync.api.constant.LockType;
import java.util.HashMap;
import java.util.Map;
/**
* 锁策略
* @author binbin.hou
* @since 0.0.1
*/
public final class Locks {private Locks(){}
/**
* MAP 信息
* @since 0.0.1
*/
private static final Map<LockType, ISyncLock> MAP = new HashMap<>();
static {MAP.put(LockType.WAIT_NOTIFY, waitNotify());
MAP.put(LockType.COUNT_DOWN_LATCH, countDownLatch());
MAP.put(LockType.CYCLIC_BARRIER, cyclicBarrier());
MAP.put(LockType.LOCK_CONDITION, lockCondition());
}
/**
* 获取锁实现
* @param lockType 锁类型
* @return 实现
* @since 0.0.1
*/
public static ISyncLock getLock(final LockType lockType) {return MAP.get(lockType);
}
/**
* @since 0.0.1
* @return 实现
*/
private static ISyncLock waitNotify() {return Instances.singleton(WaitNotifyLock.class);
}
/**
* @since 0.0.1
* @return 实现
*/
private static ISyncLock countDownLatch() {return Instances.singleton(CountDownLatchLock.class);
}
/**
* @since 0.0.1
* @return 实现
*/
private static ISyncLock lockCondition() {return Instances.singleton(LockConditionLock.class);
}
/**
* @since 0.0.1
* @return 实现
*/
private static ISyncLock cyclicBarrier() {return Instances.singleton(CyclicBarrierLock.class);
}
}
上述的锁实现都是线程平安的,所以全副应用单例模式创立。
LockType 类是一个锁的枚举类,会在注解中应用。
小结
好了,到这里咱们就把上一节中的常见的 4 种锁策略就封装实现了。
你可能好奇上下文的工夫信息哪里来?这些锁又是如何被调用的?
咱们将通过注解 + 字节码加强的形式来实现调用(就是 aop 的原理),因为篇幅起因,字节码篇幅较长,为了浏览体验,实现局部将放在下一节。
感兴趣的能够关注一下,便于实时接管最新内容。
感觉本文对你有帮忙的话,欢送点赞评论珍藏转发一波。你的激励,是我最大的能源~
不晓得你有哪些播种呢?或者有其余更多的想法,欢送留言区和我一起探讨,期待与你的思考相遇。
文中如果链接生效,能够点击 {浏览原文}。