
文章插图
因此整个自定义加锁的流程如下:
- 调用MyLock的lock(),lock()方法调用AQS的acquire()方法
- 在acquire()方法中调用了tryAcquire()方法进行加锁
- 而tryAcquire()方法在AQS中是一个必须让子类自定义重写的方法,否则会抛出一个异常
- 因此调用tryAcquire()时实际上是调用了我们自定义的MySync类中tryAcquire()方法
AQS作为JAVA并发体系下的关键类,在各种并发工具中都有它的身影,如ReentrantLock、Semaphore等 。这些并发工具用于控制sync互斥的手段都是采用AQS,外加Cas机制 。AQS采用了模板方法设计模式让子类们自定义sync互斥的条件,比如本案例中MySync类重写了tryAcquire方法 。下面实现一个自定义的sync:
public class SelfSynchronizer {private final Sync sync = new Sync();public void lock() {sync.acquire(1);}public boolean tryLock() {return sync.tryAcquire(1);}public boolean unLock() {return sync.release(1);}static class Sync extends AbstractQueuedSynchronizer {//是否处于占用状态@Overrideprotected boolean isHeldExclusively() {return getState() == 1;}/*** 获取sync资源* @param acquires* @return*/@Overridepublic boolean tryAcquire(int acquires) {if(compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());return true;}//这里没有考虑可重入锁/*else if (Thread.currentThread() == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}*/return false;}/*** 释放sync资源* @param releases* @return*/@Overrideprotected boolean tryRelease(int releases) {int c = getState() - releases;boolean free = false;if (c == 0) {free = true;}setState(c);return free;}}}复制代码ReentrantLock源码和上面自定义的sync很相似,测试下该sync,i++在多线程下执行情况:【「Java原理探索」「AQS」教你自定义实现自己的同步器】
public class TestSelfSynchronizer {private static int a = 0;private static int b = 0;private static SelfSynchronizer selfSynchronizer = new SelfSynchronizer();private static ThreadPoolExecutor executor = new ThreadPoolExecutor(20, 50, 1, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());private static ExecutorService ec = Executors.newFixedThreadPool(20);public static void main(String[] args) throws InterruptedException {for (int i = 0; i < 20 ; i++) {executor.submit(new Task());}for (int j = 0; j < 20 ; j++) {ec.submit(new TaskSync());}Thread.sleep(10000);System.out.println("a的值:"+ a);System.out.println("b的值" + b);executor.shutdown();ec.shutdown();}static class Task implements Runnable {@Overridepublic void run() {for(int i=0;i<10000;i++) {a++;}}}static class TaskSync implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {//使用sync器加锁selfSynchronizer.lock();b++;selfSynchronizer.unLock();}}}}复制代码开启两个线程池,对int型变量自增10000次,如果不加sync器,最后值小于200000,使用了自定义sync器则最后值正常等于200000,这是因为每次自增操作加锁
作者:李浩宇Alex
链接:
https://juejin.cn/post/6989937347429302280
来源:掘金
著作权归作者所有 。商业转载请联系作者获得授权,非商业转载请注明出处 。
推荐阅读
- Java循环结构——switch语句
- Javascript 中New 操作符 解读
- 浏览器的工作原理是怎样的?是如何把网页显示出来的?
- 不仅限于Java 我们必须要了解的Java位运算
- 长期淡斑美白喝什么茶,玫瑰花茶和什么搭配祛斑美白
- 重学SpringMVC:框架原理解读 + 简单入门程序+组件分析.
- Google 关键字的「搜寻量」收录指数:如何使用这个数据指标?
- 为什么我们总是推荐Java?Java为什么值得学?
- 学Java还是前端?我是这么看的
- Java开发环境搭建与配置,最全手册看这一篇就够了
