Executor框架下线程池的使用以及体验

Executor框架下线程池的使用以及体验


背景:向redis中插入5000条数据,同时将这5000条数据保存到本地的.txt文件中,单线程以及多线程环境下的处理。


1.配置JedisPool,获得Jedis对象实例

项目本身是Spring-boot项目,但这里我们不使用Spring-boot封装的spring-data-starter-redis,而使用原生的Jedis来进行操作。

public static Jedis getJedis() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxWaitMillis(30000); //最大等待时间
        jedisPoolConfig.setMaxTotal(50); //总连接数
        jedisPoolConfig.setMaxIdle(5);   //最大空闲连接数
        JedisPool jedisPool = new JedisPool(jedisPoolConfig,"xx.xx.xx.xx",
                6379,30000,"xxxxx",1);
        Jedis jedis = jedisPool.getResource();
        return jedis;
    }

查看JedisPool类的源码,可以发现它有许多的构造方法。在这里我们使用其中的一个,传递的参数依此是:jedisPoolConfig,redis服务器地址,端口号,超时时间,redis登陆校验密码(如果有配置密码的话),redis中数据库的编号


单线程环境

public static void main(String[] args) throws Exception{
        long start = System.currentTimeMillis();
        User user = new User();
        user.setNickname("777");
        Jedis jedis = JedisFactory.getJedis();
        File file = new File("D:\\图片\\token.txt");
        FileWriter writer = new FileWriter(file,true);
        for (int i=0; i < 5000 ; i++) {
            System.out.println(i);
            user.setId(i);
            String token = UUIDUtil.uuid();
            jedis.set("UserKey:"+token, JSON.toJSONString(user));
            writer.write(token);
            writer.write("\r\n");
        }
        jedis.close();
        writer.close();
        long time = System.currentTimeMillis() - start;
        System.out.println("任务全部完成共耗费时间"+Long.toString(time));
    }


public static String uuid() {
        return UUID.randomUUID().toString().replace("-","");
}

在D盘创建了一个token.txt的文本文件,创建User对象,所有的user的nickname属性都相同。利用for循环5000次,每次都为user对象设置一个新的Id,随机生成一个UUID作为token。存入redis中的K=Userkey:+token,V=利用fastjson将user对象序列化成Json。同时将所有生成的token存入token.txt文件中。


经过多次测试,平均的完成时间在五分钟左右,这显然是很漫长且不可忍受的。所以我进行了多线程操作。


多线程环境

多线程环境下的业务逻辑代码,跟单线程环境类似,所以就不贴出来了。重点在如何利用Executor框架开辟线程池

 public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        int count = 50;
        ExecutorService executorService = Executors.newCachedThreadPool();
        CountDownLatch countDownLatch = new CountDownLatch(count);
        for(int i = 0 ; i < count ; i++){
            int id = i*(5000/count)+1;
            executorService.execute(()->{
                try {
                    ConTest.write(id);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        long time = System.currentTimeMillis()-start;
        System.out.println("任务全部完成共耗费时间"+Long.toString(time));
    }
ExecutorService executorService = Executors.newCachedThreadPool();

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

CountDownLatch countDownLatch = new CountDownLatch(count)

countDownLatch是java.util.concurrent包下的一个类,它使用一个计数器来控制主线程与子线程的交互。每当一个子线程完成的时候,我们就调用 countDownLatch.countDown() 方法使计数器的值1。当计数器的值减为0,则表示所有的子线程都已完成,使用 countDownLatch.await方法主线程则可以继续运行。
在CountDownLatch 的构造方法中,我们传入的参数就是计数器的值,这里是50。所以我们的循环需要执行50次,分派50个线程。

经过多次测试,多线程环境下的耗时在7–20秒之间,效率可谓是大大提高。
多线程

但并不是说创建的线程越多,则执行的时间就越短。这取决于我们机器的硬件设备。当线程过多,CPU无法及时分配时间片,会造成多个线程的等待。这样一来执行的效率反而会大大降低。所以具体分配多少个线程,需要根据硬件的水平来决定。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值