一、背景
想象一个场景,如果我们有一个需求是要安排工作人员对CSDN发布的文章做人工审核,且每天的审核工作人员可能不一样(因为调班、请假等原因),那么我们就需要记录每天的工作排班,记录当天排班的审核人员账号,存储格式如图的account字段,以逗号分割,代表当天的审核人员的ID。然后我们每天都要对账号进行处理,判断某个工作人员的账号是否在当天的排班当中,来决定是给该工作人员分配审核任务。
二、遇到的问题
处理账号时,内存占用大
在安排当天的排班时,我们要从MySQL取出账号字符串“1,2,3,4,5,6,7,8,9…”,如果账号数量成千上万,那么数组或者List就会有成千上万个元素。
如果存储账号用的是Int类型数组,每个元素将占用4个字节内存,一个10000000个元素的数组,就占用了40000016字节的内存,相当于10000000*4/1024/1024=38M的内存,如果数据量更大占用的内存将更多,这对服务器内存来说是巨大的损耗。
三、解决方案
我们结合Java提供的BitSet机制,从数据库取出account字段后,对字符串做一次split操作,再将数据转化为BitSet,这样我们在判断某个工作人员的账号是否在当天的排班时,就可以用BitSet的get操作,比如账号Id:1000,用get(1000),如果返回结果为true,则账号在BitSet中,如果返回为false,则账号不在BitSet中。
由于BitSet的实现原理是位图,也就是用下标代表账号ID,值是1或0,这样每个元素只会存1或者0,上述get(1000)就是获取下标为1000的元素值,这种存储方式大大减少了存储空间。
使用BitSet之后,占用的内存变成了24个字节,跟之前占用40000016字节,根本不是一个量级,这里内存损耗的性能问题就得到了解决。
更多有关BitSet的原理可以参考:
Java数据类型系列之BitSet(25)
Java BitSet 类