IDFactory int类型ID生成器

这个名字老记不住,一到用的时候就想不起来,还得翻以前的项目各种找。。。

在此特此记录吧

  1 public class IDFactory {
  2
  3     private static final Logger LOGGER = LoggerFactory.getLogger(IDFactory.class);
  4     /**
  5      * 使用Bitset标记所有已使用的id<br>
  6      * 不限定大小,以至于能达到 {@link Integer#MAX_VALUE}
  7      */
  8     private final BitSet idList;
  9
 10     /**
 11      * 同步锁
 12      */
 13     private final ReentrantLock lock;
 14
 15     /**
 16      * 标记下一个int的索引
 17      */
 18     private volatile int nextIndex = 0;
 19
 20     private IDFactory() {
 21         idList = new BitSet();
 22         lock = new ReentrantLock();
 23         lockIds(0);
 24
 25         LOGGER.info("IDFactory: " + getUsedCount() + " id‘s used.");
 26     }
 27
 28     private static class SingletonHolder {
 29         protected static final IDFactory INSTANCE = new IDFactory();
 30     }
 31
 32     public static final IDFactory getInstance() {
 33         return SingletonHolder.INSTANCE;
 34     }
 35
 36     /**
 37      * 下一个可用的int值
 38      *
 39      * @return
 40      */
 41     public int nextId() {
 42         try {
 43             lock.lock();
 44
 45             int id;
 46             if (nextIndex == Integer.MIN_VALUE) {
 47                 id = Integer.MIN_VALUE;
 48             } else {
 49                 id = idList.nextClearBit(nextIndex);
 50             }
 51
 52             // 当id超过Integer#MAX_VALUE后的下一个int值将是Integer#MIN_VALUE,即已经用光了
 53             if (id == Integer.MIN_VALUE) {
 54                 LOGGER.error("All id‘s are used!",new Exception("All id‘s are used!"));
 55             }
 56             idList.set(id);
 57
 58             // It ok to have Integer OverFlow here, on next ID request IDFactory
 59             // will throw error
 60             nextIndex = id + 1;
 61             return id;
 62         } finally {
 63             lock.unlock();
 64         }
 65     }
 66
 67     /**
 68      * 告诉生成器已使用了那些int值
 69      *
 70      * @param ids
 71      *            ids to lock
 72      */
 73     private void lockIds(int... ids) {
 74         try {
 75             lock.lock();
 76             for (int id : ids) {
 77                 boolean status = idList.get(id);
 78                 if (status) {
 79                     LOGGER.error("ID " + id + " is already taken, fatal error!",new Exception("ID " + id + " is already taken, fatal error!"));
 80                 }
 81                 idList.set(id);
 82             }
 83         } finally {
 84             lock.unlock();
 85         }
 86     }
 87
 88     /**
 89      * 告诉生成器已使用了那些int值
 90      *
 91      * @param ids
 92      *            ids to lock
 93      */
 94     public void lockIds(Iterable<Integer> ids) {
 95         try {
 96             lock.lock();
 97             for (int id : ids) {
 98                 boolean status = idList.get(id);
 99                 if (status) {
100                     LOGGER.error("ID " + id + " is already taken, fatal error!",new Exception("ID " + id + " is already taken, fatal error!"));
101                 }
102                 idList.set(id);
103             }
104         } finally {
105             lock.unlock();
106         }
107     }
108
109     /**
110      * 告诉生成器某int值可以重新使用
111      *
112      * @param id
113      *            id to release
114      */
115     public void releaseId(int id) {
116         try {
117             lock.lock();
118             boolean status = idList.get(id);
119             if (!status) {
120                 LOGGER.error("ID " + id + " is not taken, can‘t release it.",new Exception("ID " + id + " is not taken, can‘t release it."));
121             }
122             idList.clear(id);
123             if (id < nextIndex || nextIndex == Integer.MIN_VALUE) {
124                 nextIndex = id;
125             }
126         } finally {
127             lock.unlock();
128         }
129     }
130
131     /**
132      * 已使用的int数
133      *
134      * @return 已使用的int数
135      */
136     public int getUsedCount() {
137         try {
138             lock.lock();
139             return idList.cardinality();
140         } finally {
141             lock.unlock();
142         }
143     }
144 }

最适合用他的场景就是游戏中各种物体怪物之类的id

时间: 2024-10-19 08:52:21

IDFactory int类型ID生成器的相关文章

分布式全局ID生成器设计

项目是分布式的架构,需要设计一款分布式全局ID,参照了多种方案,博主最后基于snowflake的算法设计了一款自用ID生成器.具有以下优势: 保证分布式场景下生成的ID是全局唯一的 生成的全局ID整体上是呈自增趋势的,也就是说整体是粗略有序的 高性能,能快速产生ID,本机(I7-6400HQ)单线程可以达到每秒生成近40万个ID 只占64bit位空间,可以根据业务需求扩展在前缀或后缀拼接业务标志位转化为字符串. UUID方案 UUID:UUID长度128bit,32个16进制字符,占用存储空间多

高并发场景下System.currentTimeMillis()的性能问题的优化 以及SnowFlakeIdWorker高性能ID生成器

package xxx; import java.sql.Timestamp; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicLong; /** * 高并发场景下System.currentTimeMillis()的性能问题的优化 * <p><p> * System.currentTimeMillis()的调用比new一个普通对象要耗时的多(具体耗时高出多少我还没测试过,有人说是100

分布式唯一ID生成器Twitter

分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成. /** * Twitter_Snowflake<br> * SnowFlake的结构如下(每部分用-分开):<br> * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 -

zookeepeer ID生成器 (一)

目录 写在前面 1.1. ZK 的分布式命名服务 1.1.1. 分布式 ID 生成器的类型 UUID方案 1.1.2. ZK生成分布式ID 写在最后 疯狂创客圈 亿级流量 高并发IM 实战 系列 疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之 -25[ 博客园 总入口 ] 写在前面 ? 大家好,我是作者尼恩.目前和几个小伙伴一起,组织了一个高并发的实战社群[疯狂创客圈].正在开始高并发.亿级流程的 IM 聊天程序 学习和实战 ? 前面,已经完成一个高性能的 Java 聊天程序的四件大

mysqlint类型的长度值mysql在建表的时候int类型后的长度代表什么

详解mysql int类型的长度值 mysql在建表的时候int类型后的长度代表什么 是该列允许存储值的最大宽度吗 为什么我设置成int(1), 也一样能存10,100,1000呢. 当时我虽然知道int(1),这个长度1并不代表允许存储的宽度,但却没有一个合理的解释. 或者说对这个长度也没有真正的研究过到底代表什么, 平时都用int(11), 也不知道为什么要11位. 所以我在网上查阅了一些资料, 也仔细的看了mysql手册关于int data type的说法. 以下是每个整数类型的存储和范围

使用MyBatis查询int类型字段,返回NULL值时报异常的解决方法

当配置mybatis返回int类型时 select id="getUserIdByName" parameterType="string" resultType="int"> SELECT id FROM user WHERE userName = #{userName} </select> 会报错如下: org.springframework.web.util.NestedServletException: Request p

详解mysql int类型的长度值问题【转】

mysql在建表的时候int类型后的长度代表什么? 是该列允许存储值的最大宽度吗? 为什么我设置成int(1), 也一样能存10,100,1000呢. 当时我虽然知道int(1),这个长度1并不代表允许存储的宽度,但却没有一个合理的解释. 或者说对这个长度也没有真正的研究过到底代表什么, 平时都用int(11), 也不知道为什么要11位. 所以我在网上查阅了一些资料, 也仔细的看了mysql手册关于int data type的说法. 以下是每个整数类型的存储和范围(来自mysql手册) 类型 字

详解mysql int类型的长度值问题

我的朋友海滨问我mysql在建表的时候int类型后的长度代表什么? 是该列允许存储值的最大宽度吗? 为什么我设置成int(1), 也一样能存10,100,1000呢. 当时我虽然知道int(1),这个长度1并不代表允许存储的宽度,但却没有一个合理的解释. 或者说对这个长度也没有真正的研究过到底代表什么, 平时都用int(11), 也不知道为什么要11位. 所以我在网上查阅了一些资料, 也仔细的看了mysql手册关于int data type的说法. 以下是每个整数类型的存储和范围(来自mysql

分布式ID生成器 zz

简介 这个是根据twitter的snowflake来写的.这里有中文的介绍. 如上图所示,一个64位ID,除了最左边的符号位不用(固定为0,以保证生成的ID都是正数),还剩余63位可用. 下面的代码与图中的位数分配略有不同,除了中间部分10bit工作机器id不变,时间戳和序列号的位数是可以根据自己的需求变化的,就是说,你可以把中间的工作机器ID往左挪一挪,或往右挪一挪. 代码 /// <summary> /// 64位ID生成器,最高位为符号位,始终为0,可用位数63. /// 实例编号占10