多线程 线程池 实战

一个 java web 多线程,线程池实际案例

要求:根据接口的内容,同时运行多个sql查询,并且把返回的数据整合起来。

框架spring mvc,mybatis

单线程的代码

    MyThread myThread=new MyThread();
    @PostMapping("/sql")
    @ApiOperation(value="并发sql")
    public List<JSONObject> sql(@RequestBody JSONObject stringList)
    {
        long start=System.currentTimeMillis();   //获取开始时间
        //建立线程安全的List存储多线程返回的数据
            ArrayList<JSONObject> jsonObjectList=new ArrayList();

        stringList.forEach((key,val)->{
                if (!(val + "").isEmpty()) {
                    //通过工厂执行查询(有参)
                    jsonObjectList.addAll(Factory.getInvokeStrategy(key).Sql(JSON.parseObject(val + "")));
                } else {
                    //通过工厂执行查询(无参)
                    jsonObjectList.addAll(Factory.getInvokeStrategy(key).Sql(new JSONObject()));
                }
        });
        long end=System.currentTimeMillis(); //获取结束时间
        System.out.println("程序运行时间: "+(end-start)+"ms");
        return jsonObjectList;
    }

请求体{"xxxx":"xxxxx","xxx":"xxx","xxxx":"xxx"}(参数内容不是重点不做赘述)

同时运行3条sql时的时间

程序运行时间: 268ms

多线程代码

    MyThread myThread=new MyThread();
    @PostMapping("/sql")
    @ApiOperation(value="并发sql")
    public List<JSONObject> sql(@RequestBody JSONObject stringList)
    {
        long start=System.currentTimeMillis();   //获取开始时间
        //建立线程安全的List存储多线程返回的数据
        CopyOnWriteArrayList<JSONObject> jsonObjectList=new CopyOnWriteArrayList();
        CountDownLatch countDownLatch=new CountDownLatch(stringList.size());
        stringList.forEach((key,val)->{
            myThread.addThread(new Thread(() -> {
                if (!(val + "").isEmpty()) {
                    //通过工厂执行查询(有参)
                    jsonObjectList.addAll(Factory.getInvokeStrategy(key).Sql(JSON.parseObject(val + "")));
                    countDownLatch.countDown();
                } else {
                    //通过工厂执行查询(无参)
                    jsonObjectList.addAll(Factory.getInvokeStrategy(key).Sql(new JSONObject()));
                    countDownLatch.countDown();
                }
            }));
        });
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long end=System.currentTimeMillis(); //获取结束时间
        System.out.println("程序运行时间: "+(end-start)+"ms");
        return jsonObjectList;
    }

程序运行时间: 93ms

速度提升三倍,

下面来讲一下上面的多线程代码

myThread是我自己随便封装的线程池

public class MyThread {

   private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 100, TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<Runnable>(500));
    public void addThread(Thread thread) {
            threadPoolExecutor.execute(thread);
    }
    public int getActiveCount (){
        return threadPoolExecutor.getActiveCount() ;
    }

    /**
     * 结束线程池(不能向线程池中添加新的线程)
     */
    public void end(){
        threadPoolExecutor.shutdown();
    }
    public boolean isEnd(){
       return threadPoolExecutor.isTerminated();
    }

}

既然是多线程,那原本的用于存储返回值的list由于线程不安全,不可以使用。这里可以用java提供的

CopyOnWriteArrayList

继承了list同时又是线程安全的。

   CopyOnWriteArrayList<JSONObject> jsonObjectList=new CopyOnWriteArrayList();

利用线程池新建和管理子线程。(中间的业务代码,是标准的利用Spring自动注册的工厂,不清楚的可以自行去了解)

       stringList.forEach((key,val)->{
            myThread.addThread(new Thread(() -> {
                if (!(val + "").isEmpty()) {
                    //通过工厂执行查询(有参)
                    
              jsonObjectList.addAll(Factory.getInvokeStrategy(key).Sql(JSON.parseObject(val + "")));
                    countDownLatch.countDown();
                } else {
                    //通过工厂执行查询(无参)
                    jsonObjectList.addAll(Factory.getInvokeStrategy(key).Sql(new JSONObject()));
                    countDownLatch.countDown();
                }
            }));
        });

子线程在线程池的管理下自动执行,但此时的主线程,也在运行。由于主线程不需访问数据库,主线程会先于子线程把数据传出去,此时传出的数据就会是空值。

因此我们需要,让主线程停下来等待子线程执行完毕。

阻塞主线程的办法有很多,如添加while,join,或者用CountDownLatch计数,

额外注意一下,由于使用了线程池,子线程可能不会自动结束,因此利用join阻塞主线程的方法在这里无法使用。

这里我使用CountDownLatch

CountDownLatch countDownLatch=new CountDownLatch(stringList.size());
         myThread.addThread(new Thread(() -> {
                if (!(val + "").isEmpty()) {
                    //通过工厂执行查询(有参)
                    jsonObjectList.addAll(Factory.getInvokeStrategy(key).Sql(JSON.parseObject(val + "")));
                    countDownLatch.countDown();
                } else {
                    //通过工厂执行查询(无参)
                    jsonObjectList.addAll(Factory.getInvokeStrategy(key).Sql(new JSONObject()));
                    countDownLatch.countDown();
                }
            }));
    try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

到这里,代码就结束了。

个人认为这是一种很优雅的写法,尽可能的简化了代码,(使用原生的lock锁简直是让人抓狂)

以上观点皆为菜鸟瞎说,如有错误,欢迎指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值