如何只用4个byte保存用户一个月的签到状态

一、思路

    使用位操作。思路很简单,一个月最多31天,四个字节有32位,每个bit位代表一天,签到则置为1,默认是0代表没签到。

二、代码

public class SigningManager {

    /**
     * 使用一个32位的int型整数表示签到状态,每个bit位代表月份中的一天,当天签到了则置1
     * 只需使用4byte就能保存一个月的签到状态信息
     * redis有相同实现
     */
    private int element;

    public SigningManager() {
        this.element = 0;
    }

    /**
     * 当天签到
     *
     * @return 签到成功true, 失败false
     */
    public boolean signToday() {
        int dayOfMonth = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
        int old = this.element;
        element |= 1 << (dayOfMonth - 1);
        return element != old;
    }

    /**
     * 查询当月某天是否签到
     *
     * @param dayOfMonth 当月第几天
     * @return 签到返回true, 否则false
     */
    public boolean getSignStatus(int dayOfMonth) {
        return (element & (1 << (dayOfMonth - 1))) != 0;
    }

    /**
     * @return 当月签到次数
     */
    public int getSignDays() {
        return Integer.bitCount(element);
    }

三、代码解析

1.使用一个int型变量element保存一个月的签到状态,初始值是0,此时32个bit位上都是0,假设今天是当月的第7天,签到后则将第七个bit位设为1。怎么做?1<<(dayOfMonth-1),用1(二进制...0000001)左移6(7-1)位,变为:...001000000,这步操作相当于定位了第七天,最后将element与...001000000取或操作。什么是取或,即两个bit位只要有一个是1结果即为1,全部是0则为0,完全等同于两个Boolean做“||”运算,现在...001000000在第七位已经是1了,其他位都是0,故取或后element的第七位也会变成1,其他位保持不变,这样我们就成功签到了。

2.获取第n天的签到状态与上述类似,先通过1<<(dayOfMonth-1)定位到第dayOfMonth天,然后与element取与操作,如果未签到,第dayOfMonth位是0,取与后变为0,说明未签到,反之说明已经签到了。

3.其实redis已经为我们实现了类似的功能。redis中有个redis.setBit(key offset value)的方法,签到可以这样做:redis.setBit(sign:user_id,7,1),这就代表user_id的用户第七天签到了,这个方法的好处就是极大的减少占用的内存,因为我们只需要一个bit位就能代表一个签到状态。继续发散,使用bit操作还能实现海量数据排重,怎么说?假如一篇文章需要实时显示阅读量,而同一个用户多次阅读只增加一次阅读量,这样你是不是要维护一个已经阅读过该文章的用户集合呢?用户量小时尚且没问题,一旦数据量大了问题就棘手了,一个可行的方案是使用bit操作对已阅读用户进行状态标记,具体细节就不赘述了。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值