zoukankan      html  css  js  c++  java
  • CountDownLatch, CyclicBarrier and Semaphore

    Reference:

    [1] http://shazsterblog.blogspot.co.uk/2011/12/comparison-of-countdownlatch.html

    CountDownLatch vs CyclicBarrier

    1. CountDownLatch can not be reused after meeting the final count.

    2. CountDownLatch can not be used to wait for Parallel Threads to finish.

    3. CyclicBarrier can be reset thus reused

    4. CyclicBarrier can be used to wait for Parallel Threads to finish.

    CountDownLatch

    CountDownLatch can be used to monitor the completion of the Children Threads if the size of the created children is known forehand. CountDownLatch enables a Thread or Threads to wait for completion of Children Threads. But there is no waiting amongst the Children until they finish each others tasks. Children may execute asynchronously and after their work is done will exit making a countdown.

     

    Practical Example : Main thread creates 10 Database Connections and Creates 10 different Threads and assigns those DB connection to the threads one each. But the Main thread must wait until all 10 Threads finish their DB Operation before closing the DB Connections. Children will exit after performing the DB Operation. A CountDownLatch can be used in this scenario.

    import java.util.concurrent.*;
    import java.util.*;
    import java.text.*;
    /**
     * @author Shazin Sadakath
     *
     */
    public class CountDownLatchTest {
        private static final int MAX_THREADS = 5;
    
        public static void main(String[] args) throws Exception {
            CountDownLatch countDownLatch = new CountDownLatch(MAX_THREADS);
        
            System.out.println("Spawning Threads");
            for(int i=0;i<MAX_THREADS;i++) {
                Thread t = new Thread(new WorkerThread(countDownLatch, String.format("Thread-%d", i)));
                t.start();
            }
            System.out.println("Spawning Finished");
            System.out.println("Waiting All Threads to Finish");
            countDownLatch.await(); // Await is void
            System.out.println("All Threads are Finished");
        }
        
        private static class WorkerThread implements Runnable {
            private CountDownLatch countDownLatch;
            
            private String name;
            
            public WorkerThread(CountDownLatch countDownLatch, String name) {
                this.name = name;
                this.countDownLatch = countDownLatch;
            }
            
            public void run() {
                try {
                    SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");                
                    System.out.printf("%s : Doing Some Work on %s
    ", getFormattedDate(sdf), name);
                    Thread.sleep(getRandomWaitTime());
                    System.out.printf("%s : Doing Some more work on %s
    ", getFormattedDate(sdf), name);
                    Thread.sleep(getRandomWaitTime());
                    System.out.printf("%s : Finished work on %s
    ", getFormattedDate(sdf), name);
                    countDownLatch.countDown(); 
                    System.out.printf("%s : Count Down Latch count on %s is %d
    ", getFormattedDate(sdf), name, countDownLatch.getCount());
                } catch(Exception e) {
                    e.printStackTrace();
                }
            }
            
            private String getFormattedDate(SimpleDateFormat sdf) {
                return sdf.format(new Date());
            }
            
            private int getRandomWaitTime() {
                return (int) ((Math.random() + 1) * 1000);
            }
            
        }
    }

    CyclicBarrier

    CyclicBarrier can be used to create a set of Children Threads if the size of the Threads created is known forehand. CyclicBarrier can be used to implement waiting amongst Children Threads until all of them finish. This is useful where parallel threads needs to perform a job which requires sequential execution. For example 10 Threads doing steps 1, 2, 3, but all 10 Threads should finish step one before any can do step 2. Cyclic barrier can be reset after all Threads are finished execution. This is a distinguishing feature from a CountDownLatch. A CountDownLatch can only be used for a single count down. Additionally a CyclicBarrier can be assigned an Additional Thread which executes each time all the Children Threads finish their respective tasks.


    Practical Example : Processing of a Image Pixels Matrix row by row in the first step and in the second step saving the Pixel values to file row by row. In this scenario if there are 10 Threads running simultaneously to process the matrix row by row then all 10 should wait until all are finished before they move on to the next step which is saving those rows to file.

    import java.util.concurrent.*;
    import java.util.*;
    import java.text.*;
    /**
     * @author Shazin Sadakath
     *
     */
    public class CyclicBarrierTest {
        private static final int MAX_THREADS = 5;
    
        public static void main(String[] args) {
            CyclicBarrier cyclicBarrier = new CyclicBarrier(MAX_THREADS, new Runnable() {
                private int count = 1;
            
                public void run() {
                    System.out.printf("Cyclic Barrier Finished %d
    ", count++);
                }
            });
        
            System.out.println("Spawning Threads");
            for(int i=0;i<MAX_THREADS;i++) {
                Thread t = new Thread(new WorkerThread(cyclicBarrier, String.format("Thread-%d", i)));
                t.start();
            }
            System.out.println("Spawning Finished");
        }
        
        private static class WorkerThread implements Runnable {
            private CyclicBarrier cyclicBarrier;
            
            private String name;
            
            public WorkerThread(CyclicBarrier cyclicBarrier, String name) {
                this.name = name;
                this.cyclicBarrier = cyclicBarrier;
            }
            
            public void run() {
                try {
                    SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");                
                    System.out.printf("%s : Doing Step 1 Work on %s
    ", getFormattedDate(sdf), name);
                    Thread.sleep(getRandomWaitTime());
                    System.out.printf("%s : Doing Step 1 more work on %s
    ", getFormattedDate(sdf), name);
                    Thread.sleep(getRandomWaitTime());
                    System.out.printf("%s : Finished Step 1 work on %s
    ", getFormattedDate(sdf), name);
                    int count = cyclicBarrier.await(); // Await returns an int which is the arrival index 1 means first 0 means last
                    System.out.printf("%s : Cyclic Barrier count on %s is %d
    ", getFormattedDate(sdf), name, count);
                    if(count == 0) {
                        cyclicBarrier.reset();
                    }
                    System.out.printf("%s : Doing Step 2 Batch of Work on %s
    ", getFormattedDate(sdf), name);
                    Thread.sleep(getRandomWaitTime());
                    System.out.printf("%s : Doing Some more Step 2 Batch of work on %s
    ", getFormattedDate(sdf), name);
                    Thread.sleep(getRandomWaitTime());
                    System.out.printf("%s : Finished Step 2 Batch of work on %s
    ", getFormattedDate(sdf), name);
                    count = cyclicBarrier.await();
                    System.out.printf("%s : Cyclic Barrier count end of Step 2 Batch of work on %s is %d
    ", getFormattedDate(sdf), name, count);
                } catch(Exception e) {
                    e.printStackTrace();
                }
            }
            
            private String getFormattedDate(SimpleDateFormat sdf) {
                return sdf.format(new Date());
            }
            
            private int getRandomWaitTime() {
                return (int) ((Math.random() + 1) * 1000);
            }
            
        }
    }

     

    Semaphore

    Semaphore can be used to create a set of Children Threads even when the size of the Threads to be created is not known forehand. This is because a Semaphore can wait until a number of releases have been made but that number is not required to initialize the Semaphore. Semaphores can be used in other scenarios such as Synchronizing between different threads such as Publisher, Subscriber scenario.

     

    Practical Example : Traversing through a folder with sub folders within sub folders and if  JPEG files are found, move them to a destination directory and then zip them. In this scenario the folder traversing is done recursively until a JPEG file is found. And then a Thread is invoked to move it to destination directory. But zipping needs to wait until all JPEG files are moved to the destination directory. In this scenario no of JPEG files available in the folder structure is not known but the zipping needs to wait till all files are successfully moved. Ideal scenario for a Semaphore based waiting.

    import java.util.concurrent.*;
    import java.util.*;
    import java.text.*;
    /**
     * @author Shazin Sadakath
     *
     */
    public class SemaphoreTest {
        private static final int MAX_THREADS = 5;
    
        public static void main(String[] args) throws Exception {
            Semaphore semaphore = new Semaphore(0);
    
            System.out.println("Spawning Threads");
            int threadCount = 0;
            Random random = new Random();
            for(int i=0;i<MAX_THREADS;i++) {
                // Threads created will not always be MAX_THREADS
                // Because Threads are created only if Random no is Even.
                // Thus the No of Threads unknown at Semaphore Initialization
                if(random.nextInt(9999) % 2 == 0) {
                    Thread t = new Thread(new WorkerThread(semaphore, String.format("Thread-%d", i)));
                    t.start();
                    threadCount++;
                }
            }
            System.out.println("Spawning Finished");
            System.out.println("Waiting All Threads to Finish");
            semaphore.acquire(threadCount); 
            System.out.println("All Threads are Finished");
        }
        
        private static class WorkerThread implements Runnable {
            private Semaphore semaphore;
            
            private String name;
            
            public WorkerThread(Semaphore semaphore, String name) {
                this.name = name;
                this.semaphore = semaphore;
            }
            
            public void run() {
                try {                
                    SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");                
                    System.out.printf("%s : Doing Some Work on %s
    ", getFormattedDate(sdf), name);
                    Thread.sleep(getRandomWaitTime());
                    System.out.printf("%s : Doing Some more work on %s
    ", getFormattedDate(sdf), name);
                    Thread.sleep(getRandomWaitTime());
                    System.out.printf("%s : Finished work on %s
    ", getFormattedDate(sdf), name);
                    semaphore.release();                
                } catch(Exception e) {
                    e.printStackTrace();
                }
            }
            
            private String getFormattedDate(SimpleDateFormat sdf) {
                return sdf.format(new Date());
            }
            
            private int getRandomWaitTime() {
                return (int) ((Math.random() + 1) * 1000);
            }
            
        }
    }
  • 相关阅读:
    JS中的prototype
    Php5.3的lambda函数以及closure(闭包)
    JavaScript事件委托的技术原理
    css 里层元素撑不开外层元素
    扩展VirtualBox虚拟机磁盘容量
    easyUI 条件查询 跟分页数据展示写在了一起的
    (转)Hibernate中关于多表连接查询hql 和 sql 返回值集合中对象问题
    有想去北京工作的的想法了
    第一次写oracle SQL 两个表链接查询
    第三天 SQL小记
  • 原文地址:https://www.cnblogs.com/codingforum/p/6799200.html
Copyright © 2011-2022 走看看