high-concurrent-cache
  • Introduction
  • Redis
    • redis常用命令
      • 生产环境谨慎使用keys命令
      • Redis 命令参考
    • redis客户端
      • Jedis使用指南
      • redisson
      • redis连接池
      • jedisCluster详解
      • jedisCluster+SpringMVC整合
    • redis主从模式
      • 配置方式
      • 一主多从读写分离架构
    • redis持计划机制的讲解
      • 持久化
      • RDB详解
      • AOF详解
      • RDB与AOF异同比较
    • 哨兵机制详解(sentinel)
      • 哨兵使用架构(sentinel)
      • 哨兵工作原理/哨兵如何监控redis
      • 哨兵如何高可用
      • 哨兵内部通讯原理/自动发现 Sentinel 和从服务器
      • 基于哨兵的redis高可用架构
    • redisCluster集群
      • 架构分析
      • 搭建高可用集群
      • 分区存储详解
      • java客户端使用redisCluster
    • 实战场景
      • 高性能分布式缓存
      • 实现定时消息通知
      • 简单高速队列的实现与应用
      • 实现去重幂等性
      • 数据计数/订单号生成
      • 基于redis实现分布式锁
      • 排行榜
      • 使用Redis bitmaps进行快速、简单、实时统计
      • 利用Redis集合(Set)统计新增用户和次日留存率
    • Redis回收进程如何工作的? Redis回收使用的是什么算法?
    • Redis持久化数据和缓存怎么做扩容?
    • Redis 分区的优势、不足以及分区类型
    • Redis 大量数据插入
    • redis实现简单延时队列
    • 使用 redis 如何设计分布式锁?说一下实现思路?使用 zk 可以吗?如何实现?这两种有什么区别?
    • Redis的bitmap讲解
    • 分布式锁的漫画教程
  • Memcached
    • Memcached概念
    • 安装配置
      • Linux安装
      • Windows安装
    • 集群搭建
    • 常用场景
    • 客户端命令
      • 客户端连接命令
      • Memcached 存储命令
        • Memcached set 命令
        • Memcached add 命令
        • Memcached replace 命令
        • Memcached append 命令
        • Memcached prepend 命令
        • Memcached CAS 命令
      • Memcached 查找命令
        • Memcached get 命令
        • Memcached gets 命令
        • Memcached delete 命令
        • Memcached incr 与 decr 命令
      • Memcached 统计命令
        • Memcached stats 命令
        • Memcached stats items 命令
        • Memcached stats slabs 命令
        • Memcached stats sizes 命令
        • Memcached flush_all 命令
    • Java客户端
    • memcached特点与redis区别
    • 一致性哈希算法原理
    • Memcache 高可用集群之magent实现主从
  • 互联网缓存架构设计
    • 常见的缓存架构方案
    • 缓存雪崩的解决方案
    • 缓存穿透的解决方案
    • 缓存击穿的解决方案
Powered by GitBook
On this page
  • 一、什么是BitSet?
  • 二、Java BitSet实现原理
  • 三、使用场景

Was this helpful?

  1. Redis
  2. 实战场景

使用Redis bitmaps进行快速、简单、实时统计

一、什么是BitSet?

注:以下内容来自JDK API:

BitSet类实现了一个按需增长的位向量。位Set的每一个组件都有一个boolean值。用非负的整数将BitSet的位编入索引。可以对每个编入索引的位进行测试、设置或者清除。通过逻辑与、逻辑或和逻辑异或操作,可以使用一个 BitSet修改另一个BitSet的内容。

默认情况下,set 中所有位的初始值都是false。

每个位 set 都有一个当前大小,也就是该位 set 当前所用空间的位数。注意,这个大小与位 set 的实现有关,所以它可能随实现的不同而更改。位 set 的长度与位 set 的逻辑长度有关,并且是与实现无关而定义的。

二、Java BitSet实现原理

在java中,BitSet的实现位于java.util包中:

public class BitSet implements Cloneable, java.io.Serializable 
{
    private final static int ADDRESS_BITS_PER_WORD = 6;
    private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
    private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1;

    /* Used to shift left or right for a partial word mask */
    private static final long WORD_MASK = 0xffffffffffffffffL;

    private static final ObjectStreamField[] serialPersistentFields =
     {
        new ObjectStreamField("bits", long[].class),
    };

    /**
     * The internal field corresponding to the serialField "bits".
     */
    private long[] words;

    .....
}

可以看到,BitSet的底层实现是使用long数组作为内部存储结构的,所以BitSet的大小为long类型大小(64位)的整数倍。

它有两个构造函数:

1、BitSet():创建一个新的位 set,默认大小是64位。

public BitSet() 
{
        initWords(BITS_PER_WORD);
        sizeIsSticky = false;
}

2、BitSet(int nbits):创建一个位set,它的初始大小足以显式表示索引范围在 0 到 nbits-1 的位。

public BitSet(int nbits)
     {
        // nbits can't be negative; size 0 is OK
        if (nbits < 0)
            throw new NegativeArraySizeException("nbits < 0: " + nbits);
        initWords(nbits);
        sizeIsSticky = true;
    }

注:

1、如果指定了bitset的初始化大小,那么会把他规整到一个大于或者等于这个数字的64的整倍数。比如64位,bitset的大小是1个long,而65位时,bitset大小是2个long,即128位。做这么一个规定,主要是为了内存对齐,同时避免考虑到不要处理特殊情况,简化程序。

2:BitSet的size方法:返回此 BitSet 表示位值时实际使用空间的位数,值是64的整数倍

length方法:返回此 BitSet 的“逻辑大小”:BitSet 中最高设置位的索引加 1

三、使用场景

常见的应用场景是对海量数据进行一些统计工作,比如日志分析、用户数统计等。

之前在阿里的实习面试就被问到一道题:有1千万个随机数,随机数的范围在1到1亿之间。现在要求写出一种算法,将1到1亿之间没有在随机数中的数求出来?

代码示例如下:

public class Alibaba
{
    public static void main(String[] args)
    {
        Random random=new Random();

        List<Integer> list=new ArrayList<>();
        for(int i=0;i<10000000;i++)
        {
            int randomResult=random.nextInt(100000000);
            list.add(randomResult);
        }
        System.out.println("产生的随机数有");
        for(int i=0;i<list.size();i++)
        {
            System.out.println(list.get(i));
        }
        BitSet bitSet=new BitSet(100000000);
        for(int i=0;i<10000000;i++)
        {
            bitSet.set(list.get(i));
        }

        System.out.println("0~1亿不在上述随机数中有"+bitSet.size());
        for (int i = 0; i < 100000000; i++)
        {
            if(!bitSet.get(i))
            {
                System.out.println(i);
            }
        }     
    }
}

参考文档:

Previous排行榜Next利用Redis集合(Set)统计新增用户和次日留存率

Last updated 5 years ago

Was this helpful?

https://www.cnblogs.com/fvsfvs123/p/4293203.html
http://www.open-open.com/lib/view/open1406379530429.html
https://blog.csdn.net/haojun186/article/details/8482343