业务场景:

遍历9万5千多条数据判断是否在园内,原来没有使用多线程的时候查询150多秒

//渔港坐标
        Map<String, List<String>> ygzxzb = (Map<String, List<String>>) redisUtil.get("sdf");
        List<ShipPositionLastMongo> shipsNotInPort = new ArrayList<>();
        double radiusInKm = radius * NAUTICAL_MILE_TO_KM; // 转换为千米
        long startpd=System.currentTimeMillis();
        // 多线程
        ExecutorService executor = Executors.newFixedThreadPool(20);
        for (ShipPositionLastMongo ship : cachedList) {
            executor.execute(() -> {
                // 检查是否在圆内
                if (isPointInCircle(latitude,longitude,radiusInKm,ship.getPos().getY(),ship.getPos().getX())) {
                    List<BigDecimal> laterPosition = Arrays.asList(new BigDecimal(ship.getPos().getX()), new BigDecimal(ship.getPos().getY()));
                    boolean isInPort = ygzxzb.values().stream().anyMatch(jwdxx -> detectMovement(laterPosition, jwdxx));
                    //如果遍历结束后 isInPort 仍为 false,则将 ship 添加到 shipsNotInPort 列表中。
                    if (!isInPort) {
                        shipsNotInPort.add(ship);
                    }
                }
            });
        }
        executor.shutdown();
        while (!executor.isTerminated()) {
            // 等待所有线程完成
        }
        log.info("判断获取渔港信息 {}",System.currentTimeMillis()-startpd);
        return shipsNotInPort;

使用多线程之后查询本地只有30多秒,线上只有5秒多

几种常见的线程池

1、newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行

2、newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待,
3、newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
4、newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行,

关闭线程池

关闭线程池可以调用shutdownNow和shutdown两个方法来实现
1、shutdownNow:对正在执行的任务全部发出interupt(),停止执行,对还未开始执行的任务全部取消,并且返回还没开始的任务列表
2、shutdown:当我们调用shutdown后,线程池将不再接受新的任务,但也不会去强制终止已经提交或者正在执行中的任务

用线程池的isTerminated()方法看是否还有没有完成的任务

调用这个方法首先要调用shutdown()或者shutdownNow(),停止提交新的任务,不然调用isTerminated()一直为false。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐