当前位置: 首页 > 科技观察

JUC-CountDownLach原理分析

时间:2023-03-22 15:31:35 科技观察

CountDownLach加锁背景CountDownLatch是Java1.5引入的,与之一起引入的工具类有CyclicBarrier、Semaphore、ConcurrenthashMap和BlockingQueue。在java.util.cucurrent包下。概念CountDownLatch这个类让一个线程在执行之前等待其他线程完成它们的执行。它是通过一个计数器来实现的,计数器的初始值就是线程数。每当执行线程时,计数器的值为-1。当计数器的值为0时,表示所有线程都执行完了,这时等待锁的线程就可以恢复工作了。源码countDownLatch类只提供了一个构造函数publicCountDownLatch(intcount){if(count<0)thrownewIllegalArgumentException("count<0");this.sync=newSync(count);}类中最常用的三个方法important//调用await()方法的线程会被挂起,等待计数值为0后才继续执行publicvoidawait()throwsInterruptedException{sync.acquireSharedInterruptibly(1);}//类似await()方法,除了它等待一定的时间后,如果计数值在指定时间后还没有变为0,它会继续执行publicbooleanawait(longtimeout,TimeUnitunit)throwsInterruptedException{returnssync.tryAcquireSharedNanos(1,unit.toNanos(timeout));}//计数值减1publicvoidcountDown(){sync.releaseShared(1);}示例常见例子:publicclassCountDownLatchTest{publicstaticvoidmain(String[]args){finalCountDownLatchlatch=newCountDownLatch(2);System.输出.println("主线程开始执行...");//先执行子线程ExecutorServicees1=Executors.newSingleThreadExecutor();es1.execute(newRunnable(){@Overridepublicvoidrun(){try{Thread.sleep(3000);System.out.println("子线程:"+Thread.currentThread().getName()+"Execute");}catch(InterruptedExceptione){e.printStackTrace();}latch.countDown();}});es1.shutdown();//第二个子线程执行ExecutorServicees2=Executors.newSingleThreadExecutor();es2.execute(newRunnable(){@Overridepublicvoidrun(){try{Thread.sleep(3000);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("子线程:"+Thread.currentThread().getName()+"执行");latch.countDown();}});es2.shutdown();System.out.println("等待两个线程完成...");try{latch.await();}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("两个子线程都执行完毕,继续执行主线程");}}结果集:主线程开始执行...等待两个线程完成…………子线程:pool-1-thread-1执行子线程:pool-2-thread-1执行两个子线程都执行完,继续执行主线程模拟并发例子:publicclassParallellimit{publicstaticvoidmain(String[]args){ExecutorServicepool=Executors.newCachedThreadPool();CountDownLatchcdl=newCountDownLatch(100);for(inti=0;i<100;i++){CountRunnablerunnable=newCountRunnable(cdl);pool.execute(runnable);}}}classCountRunnableimplementsRunnable{privateCountDownLatchcountDownLatch;publicCountRunnable(CountDownLatchcountDownLatch){this.countDownLatch=countDownLatch;}@Overridepublicvoidrun(){try{synchronized(countDownLatch){/***每次减少一个容量*/countDownLatch.countDown();System.out.println("threadcounts="+(countDownLatch.getCount()));}countDownLatch.await();System.out.println("concurrencycounts="+(100-countDownLatch.getCount()));}catch(InterruptedExceptione){e.printStackTrace();}}}源码分析publicclassCountDownLatch{//继承AQS实现他的模板方法(tryAcquireShared,tryReleaseShared)privatestaticfinalclassSyncextendsAbstractQueuedSynchronizer{//计数个数CountSync(intcount){setState(count);}intgetCount(){returngetState();}//AQS方法getState(),返回同步状态,这里指的是计数器值protectedinttryAcquireShared(intacquires){return(getState()==0)?1:-1;}//循环+cas重试,直到计数器为0,jumpout,然后释放(实现aqs共享模式释放方法)protectedbooleantryReleaseShared(intreleases){//Decrementcount;signalwhentransitiontozerofor(;;){intc=getState();if(c==0)returnfalse;intnextc=c-1;if(compareAndSetState(c,nextc))returnnextc==0;}}}privatefinalSyncsync;//实例化publicCountDownLatch(intcount){if(count<0)thrownewIllegalArgumentException("count<0");this.sync=newSync(count);}publicvoidawait()throwsInterruptedException{sync.acquireSharedInterruptibly(1);}//等待超时publicbooleanawait(longtimeout,TimeUnitunit)throwsInterruptedException{returnssync.tryAcquireSharedNanos(1,unit.toNanos(timeout));}publicvoidcountDown(){sync.releaseShared(1);}publiclonggetCount(){returnsync.getatchCount();}}总结CountDownL和Semaphore一样,都是共享模式的资源问题。这些源码实现了AQS的模板方法,然后利用CAS+循环重试实现了各自的功能。当在RT中调用多个资源,或者依赖于其他操作执行某些操作时,可以使用该计数器。角色。