CountDownLatch与CyclicBarrier使用

                                            CountDownLatch与CyclicBarrier使用

    最近做一个路网信息图形绘制,在一张地图上绘制37条路网天气信息,显示公路实时天气信息,用颜色表示不同的天气信息。这个过程可以分为两步,第一步读取经纬度文件,将经纬度及天气颜色信息封装到Map中,第二步将点信息封装到Line2D并画在地图上,当所有的线绘制完成之后,输出图片信息。此处多线程执行37条经纬度点信息的文件读取。等待全部读取完成执行。开启37条绘制线程,等待37条线程绘制结束。将绘制的图形写入文件。此时,在第一部分结束和第二部分结束要分别汇总多线程,保证全部执行完成才能执行下一步。

package drawmap;

import com.heweather.base.common.util.WeatherUtil;
import com.heweather.job.common.util.Notifier;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

/**
 * 设定数据格式循环读取数据
 *
 * @author chengshengjie
 */
public class FormatterTest {

    //坐标集合
    private static List<List<List<Map>>> points = new ArrayList<>();

    //设置开关控制线程执行
    //使用java并发库concurrent控制收集点完成执行其他线程
    private final static CountDownLatch latch   = new CountDownLatch(36);
    //使用java并发库concurrent控制画图动作执行
    private final static CyclicBarrier  barrier = new CyclicBarrier(36);

    private static String BASE_PATH     = "/Users/chengshengjie/road/";
    private static String formatterPath = "formatter/";


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

        //经纬度转换
        transformLonlat2xy();
        latch.await();
        System.out.println(points.size());
        BufferedImage image;
        image = ImageIO.read(new File(BASE_PATH + "/map.jpg"));
        Graphics2D graphics2D = image.createGraphics();
        graphics2D.setStroke(new BasicStroke(1f));

        for ( int p = 0; p < points.size(); p++ ) {
            final List<List<Map>> point = points.get(p);
            Notifier.startJob(() -> {
                for ( int i = 0; i < point.size(); i++ ) {
                    List<Map> list = point.get(i);
                    for ( int l = 0; l < list.size(); l++ ) {
                        Map      pointpre = list.get(l);
                        String   color    = pointpre.get("color").toString();
                        String[] rgb      = color.split(",");
                        graphics2D.setColor(new Color(Integer.valueOf(rgb[0]), Integer.valueOf(rgb[1]), Integer.valueOf(rgb[2])));
                        Map    pointaft = list.get(l);
                        Line2D line     = new Line2D.Double(Double.valueOf(pointpre.get("x").toString()), Double.valueOf(pointpre.get("y").toString()), Double.valueOf(pointaft.get("x").toString()), Double.valueOf(pointaft.get("y").toString()));
                        graphics2D.draw(line);
                    }
                }
                barrier.await();
                return true;
            });
        }
        barrier.await();
        OutputStream outputStream = new FileOutputStream(new File(BASE_PATH + formatterPath + "barrier.jpg"));
        ImageIO.write(image, "JPEG", outputStream);
        outputStream.close();

    }

    private static void transformLonlat2xy() {

        try ( BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(BASE_PATH + formatterPath + "gf.txt")), "UTF-8")) ) {
            String lineTxt;

            while ( (lineTxt = br.readLine()) != null ) {
                if ( !WeatherUtil.isEmpty(lineTxt) ) {
                    final String line = lineTxt;
                    Notifier.startJob(() -> {
                        String[] mainTxt = line.split(":");
                        String[] tailTxt = mainTxt[0].split("_");


                        String[] start    = tailTxt[0].split(",");
                        double   startLon = Double.valueOf(start[0]);
                        double   startLat = Double.valueOf(start[1]);
                        String[] end      = tailTxt[1].split(",");
                        double   endLon   = Double.valueOf(end[0]);
                        double   endLat   = Double.valueOf(end[1]);

                        String[] arrayTxt = mainTxt[1].split("\\|");

                        List<List<Map>> units = new ArrayList<>();
                        for ( int i = 0; i < arrayTxt.length; i++ ) {
                            List<Map> unit     = new ArrayList<>();
                            String    unitLine = arrayTxt[i];
                            String[]  lonlats  = unitLine.split(" ");
                            Double    x;
                            Double    y;

                            //存储公路起始经纬度 起始点为第一段第一个经纬度   结束点为最后一段最后一个经纬度
                            String[] begin     = arrayTxt[0].split(" ")[0].split(",");
                            String[] overArray = arrayTxt[arrayTxt.length - 1].split(" ");
                            String[] over      = overArray[overArray.length - 1].split(",");
                            for ( int j = 0; j < lonlats.length; j++ ) {
                                String[] lonlat = lonlats[j].split(",");
                                x = ((Double.valueOf(lonlat[0]) - Double.valueOf(begin[0])) / (Double.valueOf(over[0]) - Double.valueOf(begin[0]))) * (endLon - startLon) + startLon;
                                y = ((Double.valueOf(lonlat[1]) - Double.valueOf(begin[1])) / (Double.valueOf(over[1]) - Double.valueOf(begin[1]))) * (endLat - startLat) + startLat;
                                Map point = new HashMap<>();
                                //将转换后的坐标值存储到point中
                                point.put("x", x);
                                point.put("y", y);
                                point.put("color", "166,124,82");
                                unit.add(point);
                            }
                            units.add(unit);
                        }
                        points.add(units);
                        latch.countDown();
                        return true;
                    });
                }
            }
        } catch ( Exception e ) {
            e.printStackTrace();
        }
    }


}

    顺便提下,在底图上绘制经纬度连线使用的方法。

  1. 首先在底图上确定道路起始点位置(一次一次试出来的),通过改变坐标点位置对比地图上信息达到一致;
    
@Test
public void drawLine80() {
    BufferedImage image;
    try {
        image = ImageIO.read(new File("/Users/chengshengjie/road/map.jpg"));
        Graphics2D graphics2D = image.createGraphics();
        graphics2D.setColor(Color.red);
        graphics2D.setStroke(new BasicStroke(1f));

        Line2D line0 = new Line2D.Double(1104.0, 938.0, 865.0, 895.0);
        graphics2D.draw(line0);

        OutputStream outputStream = new FileOutputStream(new File("/Users/chengshengjie/road/back/G80back.jpg"));

        ImageIO.write(image, "JPEG", outputStream);
    } catch ( Exception e ) {
        e.printStackTrace();
    }
}
  1. 封装数据文件,按照固定格式封装公路信息 (startX,startY_endX,endY:lon,lat lonlat lon,lat|lon,lat lonlat lon,lat|lon,lat lonlat lon,lat) startX:底图起始点X,startY底图起始点Y;| 有些公路中间有间隔分段的。       
  2. 根据起始点经纬度及起始点底图坐标将所有的点映射到底图上并连成线

注意:

线程池配置

private static final int MAX_POOL_SIZE = 2000;

/**
 * 线程池 并行执行的 数量限制
 */
private static int POOL_SIZE       = 20;
/**
 * 线程池保留线程数
 */
private static int CORE_POOL_SIZE  = 3;
/**
 * 线程池线程空闲时间 10秒
 */
private static int KEEP_ALIVE_TIME = 10;
CountDownLatch 对线程池 保留线程数 没有限制 只是统计到达屏障的线程数 不影响线程的执行

 
@Test
public void testCountDownLatch() throws Exception {

    for ( int i = 0; i < 22; i++ ) {
        final int test = i;
        Notifier.startJob(() -> {
            System.out.println(test);
            latch.countDown();  //只是统计到达屏障的线程数 不影响线程的执行
            return true;
        });
    }
    latch.await();
    System.out.println("over");
}

CyclicBarrier await线程达到屏障值才会继续    线程池保留线程数小于屏障值 则不回打破屏障继续执行  一直等待   因为没有新的线程可以被创建

@Test
public void test() throws Exception {

    for ( int i = 0; i < 5; i++ ) {
        final int test = i;
        Notifier.startJob(() -> {
            System.out.println(test);
            barrier.await();  //只执行3个线程到await
            return true;
        });
    }
    barrier.await();
    System.out.println("over");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值