• 技术文章 >Java >java教程

    如何在Java中使用多线程来防止主线程提前结束?

    PHPzPHPz2023-04-27 16:40:15转载34

    CountDownLatch

    构造方法:

    //参数count为计数值
    public CountDownLatch(int count) {};

    常用方法

    // 调用 await() 方法的线程会被挂起,它会等待直到 count 值为 0 才继续执行
    public void await() throws InterruptedException {};
     
    // 和 await() 类似,若等待 timeout 时长后,count 值还是没有变为 0,不再等待,继续执行
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {};
     
    // 会将 count 减 1,直至为 0
    public void countDown() {};

    使用案例

    应用场景

    CountDownLatch 一般用作多线程倒计时计数器,强制它们等待其他一组(CountDownLatch的初始化决定)任务执行完成。

    CountDownLatch的两种使用场景:

    场景1:模拟并发

    import java.util.concurrent.CountDownLatch;
     
    /**
     * 让多个线程等待:模拟并发,让并发线程一起执行
     */
    public class CountDownLatchTest {
        public static void main(String[] args) throws InterruptedException {
     
            CountDownLatch countDownLatch = new CountDownLatch(1);
            
            for (int i = 0; i < 5; i++) {
                new Thread(() -> {
                    try {
                        // 等待
                        countDownLatch.await();
                        String parter = "【" + Thread.currentThread().getName() + "】";
                        System.out.println(parter + "开始执行……");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }).start();
            }
     
            Thread.sleep(2000);
           
            countDownLatch.countDown();
        }
    }

    场景2:多个线程完成后,进行汇总合并

    很多时候,我们的并发任务,存在前后依赖关系;比如数据详情页需要同时调用多个接口获取数据,并发请求获取到数据后、需要进行结果合并;或者多个数据操作完成后,需要数据 check;这其实都是:在多个线程(任务)完成后,进行汇总合并的场景。

    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.CountDownLatch;
     
    /**
     * 让单个线程等待:多个线程(任务)完成后,进行汇总合并
     */
    public class CountDownLatchTest3 {
     
        //用于聚合所有的统计指标
        private static Map map = new ConcurrentHashMap();
        //创建计数器,这里需要统计4个指标
        private static CountDownLatch countDownLatch = new CountDownLatch(4);
     
        public static void main(String[] args) throws Exception {
     
            //记录开始时间
            long startTime = System.currentTimeMillis();
     
            Thread countUserThread = new Thread(() -> {
                try {
                    System.out.println("正在统计新增用户数量");
                    Thread.sleep(3000);//任务执行需要3秒
                    map.put("userNumber", 100);//保存结果值
                    System.out.println("统计新增用户数量完毕");
                    countDownLatch.countDown();//标记已经完成一个任务
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            Thread countOrderThread = new Thread(() -> {
                try {
                    System.out.println("正在统计订单数量");
                    Thread.sleep(3000);//任务执行需要3秒
                    map.put("countOrder", 20);//保存结果值
                    System.out.println("统计订单数量完毕");
                    countDownLatch.countDown();//标记已经完成一个任务
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
     
            Thread countGoodsThread = new Thread(() -> {
                try {
                    System.out.println("正在商品销量");
                    Thread.sleep(3000);//任务执行需要3秒
                    map.put("countGoods", 300);//保存结果值
                    System.out.println("统计商品销量完毕");
                    countDownLatch.countDown();//标记已经完成一个任务
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
     
            Thread countmoneyThread = new Thread(() -> {
                try {
                    System.out.println("正在总销售额");
                    Thread.sleep(3000);//任务执行需要3秒
                    map.put("countMoney", 40000);//保存结果值
                    System.out.println("统计销售额完毕");
                    countDownLatch.countDown();//标记已经完成一个任务
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            
            //启动子线程执行任务
            countUserThread.start();
            countGoodsThread.start();
            countOrderThread.start();
            countmoneyThread.start();
     
            try {
                //主线程等待所有统计指标执行完毕
                countDownLatch.await();
                long endTime = System.currentTimeMillis();//记录结束时间
                System.out.println("------统计指标全部完成--------");
                System.out.println("统计结果为:" + map);
                System.out.println("任务总执行时间为" + (endTime - startTime) + "ms");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
     
        }
    }

    接下来进入正题

    使用多线程代替for循环提高查询效率,并且防止主线程提前结束导致其他线程数据错误

    直接上代码:

    @Override
        public AppResponse getLocations() throws InterruptedException {
            List<GetLocationVO> vos = new ArrayList<>();
            vos = projectDao.getLocationOne();    
    //      原来的代码
    //        for (GetLocationVO vo : vos) {
    //            List<LocationVO> children = projectDao.getLocationChildren(vo.getId());
    //            vo.setChildren(children);
    //        }
            //改造后的代码
            Thread(vos,10);
            return AppResponse.success("查询成功",vos);
        }
     
        //此处有加锁
        public synchronized void Thread(List<GetLocationVO> list, int nThread) throws InterruptedException {
            if (CollectionUtils.isEmpty(list) || nThread <= 0 || CollectionUtils.isEmpty(list)) {
                return;
            }
            CountDownLatch latch = new CountDownLatch(list.size());//创建一个计数器(大小为当前数组的大小,确保所有执行完主线程才结束)
            ExecutorService pool = Executors.newFixedThreadPool(nThread);//创建一个固定的线程池
            for (GetLocationVO vo : list) {
                pool.execute(() -> {
                    //处理的业务
                    List<LocationVO> children = projectDao.getLocationChildren(vo.getId());
                    vo.setChildren(children);
                    latch.countDown();
                });
            }
            latch.await();
            pool.shutdown();
        }

    以上就是如何在Java中使用多线程来防止主线程提前结束?的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:亿速云,如有侵犯,请联系admin@php.cn删除
    专题推荐:Java
    上一篇:Java实现最小高度树的方法 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • Java操作pdf的工具类itext怎么处理• Java+Tomcat环境怎么部署及安装• java的SynchronousQueue是什么• java中Lombok有什么注解• Java如何实现添加页码到PDF文档
    1/1

    PHP中文网