「Java原理探索」「AQS」教你自定义实现自己的同步器( 二 )


「Java原理探索」「AQS」教你自定义实现自己的同步器

文章插图
 
因此整个自定义加锁的流程如下:
  • 调用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
来源:掘金
著作权归作者所有 。商业转载请联系作者获得授权,非商业转载请注明出处 。




推荐阅读