#Java笔记#利用JedisPool实现对Redis的多线程调用

由于公司业务上的需要,前段时间做了一阵子数据提取与转运的工作,主要运用了python和java。在开发的过程中,接触到了一些新的技术,产生了一些新的思路,在此记录一下。今天,就先来结合一次实际的数据提取经历,总结一下java如何利用JedisPool实现对Redis的多线程调用。

先大致说一下这次任务的总体思路:

由于数据量较大,所以在这里使用了多线程。整个流程主要分为两块,生产者从源数据中循环读取任务,并将任务放到redis缓冲池中;消费者从redis中获取任务,并执行,最终将数据插入到数据库中。

#Java笔记#利用JedisPool实现对Redis的多线程调用_第1张图片

Java调用redis,需要在工程中导入驱动包:jedis,点我下载

在实际测试中,生产者的执行速率很快,所以这里生产者只开了一个线程去执行。

1、生产者循环读取任务并放入redis缓冲池中:

public class RedisQueueProducer{
    private int pageNum = 0;
    private Jedis jedis;

    public void startWrite(Jedis jedis){
        this.jedis = jedis;
        MyExecutor executor = new MyExecutor();
        executor.start();
    }


    private class MyExecutor  extends Thread{
        @Override
        public void run() {
            super.run();
            List readData;
            while (true) {
                //分页从数据库中读取数据,直到数据全部取完,跳出循环
                readData = JdbcUtils.queryData(pageNum);
                if(readData.size()>0) {
                    String[] readDataArrays = new String[readData.size()];
                    jedis.lpush("sourceIds",readData.toArray(readDataArrays));
                    pageNum++;
                }else{
                    break;
                }
            }
        }
    }
}

这里存入redis使用的lpush的方式,选择这种方式的好处是读取redis数据时,调用lpop可以直接弹出list顶部的第一条数据,该条数据也会从redis中移除,不会占用空间,即取即用。

2、消费者从redis中获取任务并执行,存入数据库中:

public class RedisQueueConsumer{
    private Jedis jedis;
    private HashDocumentIdZHO hashDocumentIdZHO;

    public void startRead(Jedis jedis){
        //连接本地的 Redis 服务
        this.jedis = jedis;
        hashDocumentIdZHO =  new HashDocumentIdZHO();

        MyExecutor executor = new MyExecutor();
        executor.start();

    }

    private class MyExecutor  extends Thread{
        @Override
        public void run() {
            super.run();
            while (true){
                String sourceId = jedis.lpop("sourceIds");
                if(sourceId!=null&&!sourceId.equals("")) {
                    if(JdbcUtils.getConn()==null){
                        JdbcUtils.connect();
                    }
                    ConvertIdResult result = hashDocumentIdZHO.getHashDocumentIdZHOSoap().convertClassicID(sourceId,1,2,true);
                    HashDoc doc = new HashDoc();
                    doc.setResult(result);
                    doc.setSourceDocId(sourceId);

                    JdbcUtils.insert(doc);
                    System.out.println("线程名称:" + Thread.currentThread().getName() + ",hash值:" + result.getResult());

                }else{
                    try {
                        //如果没有数据,等待30s,再执行;后来查看jedis的api得知,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止,所以理论上这里可以不做设置。不过并没有实际试验过。
                        sleep(30000);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

3、利用jedisPool实现多线程调用:

可能有小伙伴看到这里会问,为什么要用redis作为缓冲池呢?(如果没有人问,请容我自问自答一下...)因为这里用到了多线程,而redis本身是线程安全的,所以自然这里就选择了redis作为缓冲池。不过,redis本身是单线程的,如果我们需要通过java多线程从redis取数据,则需要借助jedisPool,生成一个redis连接池,让一个线程对应一个redis连接。

public class RedisQueuePool {

    public static JedisPool jedisPool = null;

    public static void main(String[] args) {
        if(jedisPool == null){
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            jedisPoolConfig.setMaxTotal(10000);
            //控制一个pool最多有多少个状态为idle(空闲)的jedis实例
            jedisPoolConfig.setMaxIdle(8);
            //获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1
            jedisPoolConfig.setMaxWaitMillis(1);
            //获得一个jedis实例的时候是否检查连接可用性(ping());如果为true,则得到的jedis实例均是可用的;
            jedisPoolConfig.setTestOnBorrow(true);
            //return 一个jedis实例给pool时,是否检查连接可用性(ping())
            jedisPoolConfig.setTestOnReturn(true);

            jedisPool = new JedisPool(jedisPoolConfig,"localhost");
        }
        //新建20个线程,执行操作
        for (int i = 0; i < 20; i++) {
            RedisQueueConsumer consumer = new RedisQueueConsumer();
            consumer.startRead(jedisPool.getResource());
        }
    }

}

jedisPoolConfig是jedisPool的一些属性配置,详细的属性配置查看可以移步这里:属性配置列表。

如果想要使用jedisPool,还需要引入commons-pool2-2.4.2.jar。

以上就是JAVA利用JedisPool实现对Redis的多线程调用的思路与解决方案了,希望能对读到这里的你能有所帮助~

 

 

 

你可能感兴趣的:(java笔记,redis,多线程,java,jedis,jedisPool)