preface
-
Scene description
Briefly describe this step. Open three threads and call three different methods. Use the countdowncatch counter to wait for the completion of all three methods, and then merge the data
Basic concepts
-
introduce
CountDownLatch is a synchronization tool class that allows one or more threads to wait until other threads finish executing.
-
principle
CountDownLatch is implemented through a counter whose initialization value is the number of threads. Each time a thread completes its task, the value of the counter will be reduced by 1. When the counter reaches 0, it indicates that all threads have completed the task, and then the thread waiting on the lock can resume executing the task.
Pseudo code
Main thread start Create CountDownLatch for N threads Create and start N threads Main thead wait on latch N threads completes there tasks are returns Main thread resume execution
-
Applicable scenario
-
A thread waits for n threads to finish executing before starting to run. Initialize the counter of CountDownLatch to new CountDownLatch(n). Whenever a task thread finishes executing, the counter will be decremented by 1 CountDownLatch Countdown(), when the counter value becomes 0, the thread of await() on CountDownLatch will be awakened. A typical application scenario is that when starting a service, the main thread needs to wait for multiple components to load before continuing to execute.
-
Realize the maximum parallelism of multiple threads starting to execute tasks. Note that parallelism, not concurrency, emphasizes that multiple threads start executing at the same time. Similar to a race, put multiple threads at the starting point, wait for the starting gun to sound, and then start running at the same time. The method is to initialize a shared CountDownLatch(1) and initialize its calculator to 1. Multiple threads first countdownlatch before starting to execute tasks Await(), when the main thread calls countDown(), the counter changes to 0 and multiple threads are awakened at the same time.
-
-
instructions
//The thread calling the await() method is suspended and waits until the count value is 0 public void await() throws InterruptedException { }; //Similar to await(), it will continue to execute if the count value has not changed to 0 after waiting for a certain time public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //Decrement count by 1 public void countDown() { };
Implementation process
-
Function description
Simulate an application startup class, start N threads at the beginning, check whether N external services are normal and notify locking; The startup class has been waiting on the lock. Once all external services are verified and checked, the execution of the startup class will be resumed.
-
Implementation logic
-
The BaseHealthChecker abstract base class is a base class that implements the Runnable interface and is responsible for the health check of all specific external services.
-
NetworkHealthChecker.java,DatabaseHealthChecker.java and cachehealthchecker Java inherits from BaseHealthChecker and references CountDownLatch instance. Except for different service name and sleep time, they all implement their own verifyService method.
-
ApplicationStartupUtil.java: is a main startup class. It is responsible for initializing locking, and then waiting for all services to be checked before resuming execution.
-
Case code
-
BaseHealthChecker abstract base class
package link.lycreate.springbooteasyexceldemo.thread; import java.util.concurrent.CountDownLatch; /** * @ClassName BaseHealthChecker * @Description External service health check base class$ * @Author charlesYan * @Date 2021/5/13 18:13 * @Version 1.0 **/ public abstract class BaseHealthChecker implements Runnable { private CountDownLatch _latch; private String _serviceName; private boolean _serviceUp; public BaseHealthChecker(String serviceName, CountDownLatch latch) { super(); this._latch = latch; this._serviceName = serviceName; this._serviceUp = false; } @Override public void run() { try { verifyService(); _serviceUp = true; } catch (Throwable t) { t.printStackTrace(System.err); _serviceUp = false; } finally { if(_latch != null) { _latch.countDown(); } } } public String getServiceName() { return _serviceName; } public boolean isServiceUp() { return _serviceUp; } public abstract void verifyService(); }
-
Abstract base class subclass NetworkHealthChecker
package link.lycreate.springbooteasyexceldemo.thread; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * @ClassName NetworkHealthChecker * @Description TODO Network service health check$ * @Author charlesYan * @Date 2021/5/14 9:09 * @Version 1.0 **/ @Slf4j public class NetworkHealthChecker extends BaseHealthChecker { public NetworkHealthChecker(CountDownLatch latch) { super("Network Service", latch); } @Override public void verifyService() { log.info("Checking {}",this.getServiceName()); try { TimeUnit.SECONDS.sleep(7); } catch (InterruptedException e) { e.printStackTrace(); } log.info("{} is UP",this.getServiceName()); } }
-
Abstract base class subclass DatabaseHealthChecker
package link.lycreate.springbooteasyexceldemo.thread; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * @ClassName DatabaseHealthChecker * @Description Database service health check class$ * @Author charlesYan * @Date 2021/5/14 9:35 * @Version 1.0 **/ @Slf4j public class DatabaseHealthChecker extends BaseHealthChecker { public DatabaseHealthChecker(CountDownLatch latch) { super("Database Service", latch); } @Override public void verifyService() { log.info("Checking {}",this.getServiceName()); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } log.info("{} is UP",this.getServiceName()); } }
-
Abstract base class subclass CacheHealthChecker
package link.lycreate.springbooteasyexceldemo.thread; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * @ClassName CacheHealthChecker * @Description TODO Cache service health check class$ * @Author charlesYan * @Date 2021/5/14 11:26 * @Version 1.0 **/ @Slf4j public class CacheHealthChecker extends BaseHealthChecker { public CacheHealthChecker(CountDownLatch latch) { super("Cache Service", latch); } @Override public void verifyService() { log.info("Checking {}",this.getServiceName()); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } log.info("{} is UP",this.getServiceName()); } }
-
ApplicationStartupUtil main startup class
package link.lycreate.springbooteasyexceldemo.thread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; /** * @ClassName ApplicationStartupUtil * @Description Main startup class$ * @Author charlesYan * @Date 2021/5/14 11:38 * @Version 1.0 **/ public class ApplicationStartupUtil { private static List<BaseHealthChecker> _services; private static CountDownLatch _latch; private ApplicationStartupUtil() { } private final static ApplicationStartupUtil INSTANCE = new ApplicationStartupUtil(); public static ApplicationStartupUtil getInstance() { return INSTANCE; } public static boolean checkExternalServices() throws Exception { _latch = new CountDownLatch(3); _services = new ArrayList<BaseHealthChecker>(); _services.add(new NetworkHealthChecker(_latch)); _services.add(new CacheHealthChecker(_latch)); _services.add(new DatabaseHealthChecker(_latch)); Executor executor = Executors.newFixedThreadPool(_services.size()); for(final BaseHealthChecker v : _services) { executor.execute(v); } _latch.await(); for(final BaseHealthChecker v : _services) { if( ! v.isServiceUp()) { return false; } } return true; } }
-
main method test class
package link.lycreate.springbooteasyexceldemo; import link.lycreate.springbooteasyexceldemo.thread.ApplicationStartupUtil; import lombok.extern.slf4j.Slf4j; /** * @ClassName MainTest * @Description main Method test class$ * @Author charlesYan * @Date 2021/5/14 11:49 * @Version 1.0 **/ @Slf4j public class MainTest { public static void main(String[] args) { boolean result = false; try { result = ApplicationStartupUtil.checkExternalServices(); } catch (Exception e) { e.printStackTrace(); } log.info("External services validation completed !! Result was :: {}",result); } }
Output log
```log [pool-1-thread-2] INFO link.lycreate.springbooteasyexceldemo.thread.CacheHealthChecker - Checking Cache Service [pool-1-thread-3] INFO link.lycreate.springbooteasyexceldemo.thread.DatabaseHealthChecker - Checking Database Service [pool-1-thread-1] INFO link.lycreate.springbooteasyexceldemo.thread.NetworkHealthChecker - Checking Network Service [pool-1-thread-3] INFO link.lycreate.springbooteasyexceldemo.thread.DatabaseHealthChecker - Database Service is UP [pool-1-thread-2] INFO link.lycreate.springbooteasyexceldemo.thread.CacheHealthChecker - Cache Service is UP [pool-1-thread-1] INFO link.lycreate.springbooteasyexceldemo.thread.NetworkHealthChecker - Network Service is UP [main] INFO link.lycreate.springbooteasyexceldemo.MainTest - External services validation completed !! Result was :: true ```
summary
-
CyclicBarrier
CyclicBarrier adds to the specified threshold, while CountDownLatch subtracts to 0. The two are just the opposite
-
CountDownLatch
CountDownLatch is one-time. The value of the calculator can only be initialized once in the construction method. After that, there is no mechanism to set the value again. When CountDownLatch is used, it cannot be used again
-
matters needing attention
try{ //Execute code first do.... //last countDown .countDown(); }catch(Exception ex){ .countDown();//In case of any abnormality, the one above countDown() will not execute. Add this line of code to prevent thread pool OOM }
Reference link
-
Understanding and use of CountDownLatch
https://www.cnblogs.com/Lee_xy_z/p/10470181.html
-
CountDownLatch stepped on the pit
https://blog.csdn.net/u010598327/article/details/82083038
-
CountDownLatch
https://www.jianshu.com/p/4b6fbdf5a08f
-
countDownLatch
https://www.jianshu.com/p/e233bb37d2e6
-
Java concurrency – CountDownLatch Example
https://howtodoinjava.com/java/multi-threading/when-to-use-countdownlatch-java-concurrency-example-tutorial/