Java并发编程之CountDownLatch

CountDownLatch

CountDown 的意思是倒数,latch是门栓的意思,连起来就可以翻译为倒数的门栓。在我们Java体现的意思就是:在多线程的环境下,你可以规定有10个门栓(即10个线程在干活),当门栓数减到零(即每个线程完成自己的任务后会把门栓数减一,10个线程都完成后门栓数就减到了零),就可以统一执行接下来的任务。

接下来我们通过三个场景来了解 CountDownLatch 的使用:

  • 第一个场景:我们先要去数据库查询一批重量级的数据,接着对这批数据进行处理,对这批数据处理完以后还需要进行二次处理。二次处理是建立在第一次处理基础之上的,所以需要等待第一次处理完以后二次处理才可以进行。
/**
 * 在我们程序中一开始串行化处理后又遇见并行化处理了、等并行化处理完以后又要开始串行化处理、可以这么用
 */
public class CountDownLatchTest {

    private static Random random = new Random(System.currentTimeMillis());

    private static ExecutorService executor = Executors.newFixedThreadPool(2);

    private static  final CountDownLatch latch = new CountDownLatch(10);


    public static void main(String[] args) throws InterruptedException {

        // 1:查询数据 一批数据
        // 2:数据处理
        // 3:一批数据处理完 对数据进行二次处理

        //1
        int[] data = query();

        //2
        for (int i = 0; i < data.length; i++) {
            executor.execute(new SimpleRunnable(data, i,latch));
        }
      	//一直在等待,直到 latch.getCount() = 0 时才会释放,去执行下面的代码
        latch.await();
        //3
        System.out.println(" all of worker finish done ");

        executor.shutdown();


        //等待一个小时、没到也会提前结束 此方法可行、但是这次使用 countDownLatch
        //executor.awaitTermination(1, TimeUnit.HOURS);
      
      

    }


    static class SimpleRunnable implements Runnable {

        private final int[] data;

        private final int index;

        private final CountDownLatch latch;

        public SimpleRunnable(int[] data, int index ,CountDownLatch latch) {
            this.data = data;
            this.index = index;
            this.latch = latch;
        }

       // 对数据进行处理
        @Override
        public void run() {

            try {
                Thread.sleep(random.nextInt(2000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int value = data[index];
            if (value % 2 == 0) {
                data[index] = value * 2;
            } else {
                data[index] = value * 10;

            }

            System.out.println(Thread.currentThread().getName() + " finished  ");
          	//每完成一次就调用一次减一的操作、
            latch.countDown();

        }
    }


    //相当于查询数据
    private static int[] query() {
        return new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    }
}

  • 第二个场景:两个线程各自干活,而一个线程依赖另外一个线程处理好的数据才能接着干活。
public class CountDownLatchTest {


    private static final CountDownLatch latch = new CountDownLatch(1);

    public static void main(String[] args) throws InterruptedException {

        new Thread() {
            @Override
            public void run() {

                System.out.println(" --开始干活-----");
                try {
                    Thread.sleep(100);
                    System.out.println(" 干完等待别的数据进来-------");
                    latch.await();
                    System.out.println("别人数据进来了,我要开始干活了=======");

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

      
        new Thread(){
            @Override
            public void run() {
                System.out.println("开始帮别人处理数据---");
                try {
                    Thread.sleep(10);
                    System.out.println("帮别人处理的数据处理好了-------");
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
         }
        }.start();
        Thread.currentThread().join();
    }

}


  • 第三个场景:假设有一个系统会不断的爬取数据存储到多个数据库,但是数据进行校验后才能使用,现在需要对表中数据量的个数以及数据的标准性进行校验。这时我们需要监控某个表是否是已经校验完成,还需要监控某个数据的数据是否已经处理完毕。
public class CountDownLatchTest {

    private static Random random = new Random(System.currentTimeMillis());

		//事件、或者数据库
    static class Event {

        int id;

        public Event(int id) {
            this.id = id;
        }
    }


	
    interface Watcher {

        void done(Table table);
    }
  

		//检测表里面数据是否完成
    static class TaskBatch implements Watcher {

        private CountDownLatch countDownLatch;

        private TaskGroup taskGroup;


        public TaskBatch(TaskGroup taskGroup, int size) {

            this.taskGroup = taskGroup;
            this.countDownLatch = new CountDownLatch(size);
        }

        @Override
        public void done(Table table) {

            countDownLatch.countDown();

            if (countDownLatch.getCount() == 0) {
                System.out.println(" The table " + table.tableName + " finished work ,[" + table + "]");
                taskGroup.done(table);
            }


        }
    }

		//检测数据库数据是否已经处理完毕
    static class TaskGroup implements Watcher {

        private CountDownLatch countDownLatch;

        private Event event;


        public TaskGroup(int size, Event event) {
            this.countDownLatch = new CountDownLatch(size);
            this.event = event;
        }

        @Override
        public void done(Table table) {

            countDownLatch.countDown();
          
            if (countDownLatch.getCount() == 0) {
                System.out.println(" ==== All of table done in event : " + event.id);
            }


        }
    }

	  // 数据表
    static class Table {
        String tableName;
        long sourceRecordCount = 0;
        long targetCount;
        String sourceColumnSchema = "<table name = 'a'><column name ='coll' type = 'varchar2'/></table>";
        String targetColumnSchema = "";


        public Table(String tableName, long sourceRecordCount) {
            this.tableName = tableName;
            this.sourceRecordCount = sourceRecordCount;
        }

        @Override
        public String toString() {
            return "Table{" +
                    "tableName='" + tableName + '\'' +
                    ", sourceRecordCount=" + sourceRecordCount +
                    ", targetCount=" + targetCount +
                    ", sourceColumnSchema='" + sourceColumnSchema + '\'' +
                    ", targetColumnSchema='" + targetColumnSchema + '\'' +
                    '}';
        }
    }

		//给表里面添加数据
    private static List<Table> capture(Event event) {
        List<Table> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(new Table("table - " + event.id + " - " + i, i * 1000));
        }
        return list;
    }


    public static void main(String[] args) {
					//模拟有两个数据库里的数据需要处理
        Event[] events = {new Event(1), new Event(2)};

        ExecutorService service = Executors.newFixedThreadPool(5);

        for (Event event : events) {
            List<Table> tables = capture(event);
          	//检测某个数据库里面的数据是否已经处理完毕
            TaskGroup taskGroup = new TaskGroup(tables.size(), event);

            //接着对table进行校验
            for (Table table : tables) {
								//检测某个表里面的数据是否已经处理完毕
                TaskBatch taskBatch = new TaskBatch(taskGroup, 2);
                TrustSourceRecordCount recordCountRunnable = new TrustSourceRecordCount(table, taskBatch);
                TrustSourceColumns columnsRunnable = new TrustSourceColumns(table, taskBatch);

                service.submit(recordCountRunnable);
                service.submit(columnsRunnable);


            }


        }


    }

   //校验数据量是否一致
    static class TrustSourceRecordCount implements Runnable {

        private final Table table;

        private final TaskBatch taskBatch;

        public TrustSourceRecordCount(Table table, TaskBatch taskBatch) {
            this.table = table;
            this.taskBatch = taskBatch;
        }


        @Override
        public void run() {

            try {
                Thread.sleep(random.nextInt(10000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            table.targetCount = table.sourceRecordCount;

            // System.out.println(" The table " + table.tableName + " target record capture done and update  ! ");

            taskBatch.done(table);

        }


    }

		//校验数据的准确性
    static class TrustSourceColumns implements Runnable {

        private final Table table;

        private final TaskBatch taskBatch;

        public TrustSourceColumns(Table table, TaskBatch taskBatch) {
            this.table = table;
            this.taskBatch = taskBatch;
        }

        @Override
        public void run() {

            try {
                Thread.sleep(random.nextInt(10000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            table.targetColumnSchema = table.sourceColumnSchema;

            // System.out.println(" The table " + table.tableName + " target column capture done and update  ! ");

            taskBatch.done(table);
        }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值