开发者社区> 问答> 正文

[@talishboy][¥20]CountDownLatch 是否可以使用独占锁来实现?

JDK1.8的源码里面是采用AQS共享锁实现的。为什么不采用独占锁的方式实现?下面附上我独占锁实现的代码:

public class MyCountDownLatch {
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;
        Sync(int count) {
            setState(count);
        }
        int getCount() {
            return getState();
        }
        protected boolean tryAcquire(int acquires) {
            return (getState() == 0) ? true :false;
        }
        protected boolean tryRelease(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }
    private final MyCountDownLatch.Sync sync;
    public MyCountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new MyCountDownLatch.Sync(count);
    }
    public void await() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    public void countDown() {
        sync.release(1);
    }

    public long getCount() {
        return sync.getCount();
    }

    public String toString() {
        return super.toString() + "[Count = " + sync.getCount() + "]";
    }

    public static void main(String[] args) throws InterruptedException {
        MyCountDownLatch myCountDownLatch = new MyCountDownLatch(5);
        for(int i=0;i<5;i++){
            new Thread(()-> {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"start");
                myCountDownLatch.countDown();;
            }).start();
        }
        myCountDownLatch.await();
        System.out.println("所有线程执行完毕了");

    }
}

展开
收起
mywsat 2018-11-30 21:58:13 2325 0
2 条回答
写回答
取消 提交回答
  • 你这个实现针对多个线程调用await情况,无法唤醒所有线程. 不知道理解有没有问题? 我通过模仿ReentrantLock实现了一个独占访问的代码

    public class MyCountDownLatch {
    
    
        private final Sync sync ;
    
    
        public MyCountDownLatch(int state) {
            sync = new Sync(state);
        }
    
        private static final class Sync extends AbstractQueuedSynchronizer {
    
            Sync(int state) {
                setState(state);
            }
    
            @Override
            protected boolean tryAcquire(int arg) {
                return getState() == 0;
            }
            @Override
            protected boolean tryRelease(int arg) {
                for (; ; ) {
                    int c = getState();
                    if (c == 0)
                        return true;
                    int nextc = c - 1;
                    if (compareAndSetState(c, nextc))
                        return nextc == 0;
                }
            }
    
    
        }
    
        public void await() {
            try {
                sync.acquire(1);
            } catch (Exception e) {
    
                e.printStackTrace();
            } finally {
                sync.release(1);
            }
        }
    
        public void countDown() {
            sync.release(1);
        }
    
    
        public static void main(String... args) throws InterruptedException {
    
    
            MyCountDownLatch countDownLatch = new MyCountDownLatch(5);
            Thread thread1 = new Thread() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+":----->1 before await()");
                    countDownLatch.await();
                    System.out.println(Thread.currentThread().getName()+":----->1");
                }
            };
    
            Thread thread2 = new Thread() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+":----->2 before await()");
                    countDownLatch.await();
                    System.out.println(Thread.currentThread().getName()+":----->2");
                }
            };
    
            thread1.start();
            thread2.start();
            Thread.sleep(100);
            System.out.println("start");
            countDownLatch.countDown();
            countDownLatch.countDown();
            countDownLatch.countDown();
            countDownLatch.countDown();
            countDownLatch.countDown();
        }
    }
    
    
    2019-07-24 08:43:21
    赞同 展开评论 打赏
  • 孔祥坤 职位:阿里妈妈应用平台技术专家 擅长问题:分布式应用系统架构、Java核心技术以及开源framework等 经历:10年左右Java应用系统研发及架构设计经验,曾主导和参与多个重要广告应用系统的研发设计,目前在阿里妈妈从事广告投放中台的研发工作。

    先说下CountDownLatch典型的使用场景,一般都是先在主线程中创建多个工作线程(调用CountDownLatch.countDown方法),然后在主线程中调用CountDownLatch的await方法等待所有工作线程完成工作。但实际上,上面的使用场景并不是CountDownLatch唯一的一种用法,比如在主线程中创建多个工作线程(会调用CountDownLatch.countDown方法)之后,主线程可以不调用CountDownLatch.await方法来阻塞主线程,而是创建另一组工作2线程,每个工作2线程中都调用CountDownLatch.await方法阻塞自己,当第一组工作线程(调用CountDownLatch.countDown方法)全部完成之后会唤醒所有的工作2线程。这样就清楚了,所有调用CountDownLatch.await方法的线程是共享锁的。

    2019-07-17 23:17:52
    赞同 展开评论 打赏
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载