diff --git a/Codings/IdWorker.java b/Codings/IdWorker.java new file mode 100644 index 00000000..0562fcb8 --- /dev/null +++ b/Codings/IdWorker.java @@ -0,0 +1,115 @@ +public class IdWorker { + private long workerId; + private long datacenterId; + private long sequence; + + /** + * + * @param workerId 机器ID 1-32 + * @param datacenterId 数据中心ID 1-32 + * @param sequence 毫秒内序列 1-4095 + */ + public IdWorker(long workerId, long datacenterId, long sequence) { + // sanity check for workerId + // 这儿不就检查了一下,要求就是你传递进来的机房id和机器id不能超过32,不能小于0 + if (workerId > maxWorkerId || workerId < 0) { + throw new IllegalArgumentException( + String.format("worker Id can't be greater than %d or less than 0", maxWorkerId)); + } + if (datacenterId > maxDatacenterId || datacenterId < 0) { + throw new IllegalArgumentException( + String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); + } + System.out.printf( + "worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d", + timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId); + + this.workerId = workerId; + this.datacenterId = datacenterId; + this.sequence = sequence; + } + + private long twepoch = 1288834974657L; + + private long workerIdBits = 5L; + private long datacenterIdBits = 5L; + + // 这个是二进制运算,就是 5 bit最多只能有31个数字,也就是说机器id最多只能是32以内 + private long maxWorkerId = -1L ^ (-1L << workerIdBits); + + // 这个是一个意思,就是 5 bit最多只能有31个数字,机房id最多只能是32以内 + private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); + private long sequenceBits = 12L; + + private long workerIdShift = sequenceBits; + private long datacenterIdShift = sequenceBits + workerIdBits; + private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; + private long sequenceMask = -1L ^ (-1L << sequenceBits); + + private long lastTimestamp = -1L; + + public long getWorkerId() { + return workerId; + } + + public long getDatacenterId() { + return datacenterId; + } + + public long getTimestamp() { + return System.currentTimeMillis(); + } + + public synchronized long nextId() { + // 这儿就是获取当前时间戳,单位是毫秒 + long timestamp = timeGen(); + + if (timestamp < lastTimestamp) { + System.err.printf("clock is moving backwards. Rejecting requests until %d.", lastTimestamp); + throw new RuntimeException(String.format( + "Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); + } + + if (lastTimestamp == timestamp) { + // 这个意思是说一个毫秒内最多只能有4096个数字 + // 无论你传递多少进来,这个位运算保证始终就是在4096这个范围内,避免你自己传递个sequence超过了4096这个范围 + sequence = (sequence + 1) & sequenceMask; + if (sequence == 0) { + timestamp = tilNextMillis(lastTimestamp); + } + } else { + sequence = 0; + } + + // 这儿记录一下最近一次生成id的时间戳,单位是毫秒 + lastTimestamp = timestamp; + + // 这儿就是将时间戳左移,放到 41 bit那儿; + // 将机房 id左移放到 5 bit那儿; + // 将机器id左移放到5 bit那儿;将序号放最后12 bit; + // 最后拼接起来成一个 64 bit的二进制数字,转换成 10 进制就是个 long 型 + return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) + | (workerId << workerIdShift) | sequence; + } + + private long tilNextMillis(long lastTimestamp) { + long timestamp = timeGen(); + while (timestamp <= lastTimestamp) { + timestamp = timeGen(); + } + return timestamp; + } + + private long timeGen() { + return System.currentTimeMillis(); + } + + // ---------------测试--------------- + public static void main(String[] args) { + IdWorker worker = new IdWorker(1, 1, 1); + for (int i = 0; i < 30; i++) { + System.out.println(worker.nextId()); + } + } + +} diff --git a/Protobuf/protobuf-Maven.java b/Protobuf/protobuf-Maven.java index bfd3ef05..00b46b94 100644 --- a/Protobuf/protobuf-Maven.java +++ b/Protobuf/protobuf-Maven.java @@ -24,7 +24,7 @@ ${project.basedir}/proto ${project.build.sourceDirectory} - + false ${project.build.directory}/protoc-dependencies diff --git "a/Protobuf/protobuf-\347\224\237\346\210\220\347\232\204Java\345\257\271\350\261\241.java" "b/Protobuf/protobuf-\347\224\237\346\210\220\347\232\204Java\345\257\271\350\261\241.java" index b262ace2..b5c8e4fb 100644 --- "a/Protobuf/protobuf-\347\224\237\346\210\220\347\232\204Java\345\257\271\350\261\241.java" +++ "b/Protobuf/protobuf-\347\224\237\346\210\220\347\232\204Java\345\257\271\350\261\241.java" @@ -5,6 +5,14 @@ * .proto文件中定义的类, 以内部类的形式存在 * 这个文件包含一个单一的outer class定义,包含一些内嵌类和静态字段 + * 如果 proto文件的名称和里面定义的message名称一样,则生成的java文件为 OuterXxxx + user.proto -> 生成的类 UserOuterClass + |-message User + + + + + # 生成的类 * 实现 Message 接口, 并且被标识为 final diff --git a/Protobuf/protobuf.java b/Protobuf/protobuf.java index 946d3ec5..bea2c6f3 100644 --- a/Protobuf/protobuf.java +++ b/Protobuf/protobuf.java @@ -27,7 +27,21 @@ repeated int32 samples = 4 [packed=true]; * proto3已经默认使用了, 不需要手动声明 - + * 也是optional字段一样,另外加了一个count计数变量,用于标明这个字段有多少个,这样发送方发送的时候,同时发送了count计数变量和这个字段的起始地址,接收方在接受到数据之后,按照count来解析对应的数据即可。 + + optional + * 可选的 + * 就是protobuf处理的时候另外加了一个bool的变量,用来标记这个optional字段是否有值,发送方在发送的时候,如果这个字段有值,那么就给bool变量标记为true,否则就标记为false, + * 接收方在收到这个字段的同时,也会收到发送方同时发送的bool变量,拿着bool变量就知道这个字段是否有值了,这就是option的意思 + + * 这也就是他们说的所谓平滑升级,无非就是个兼容的意思。 + + + required + * 必选字段 + * proto3不让用了已经 + + # 字段编号 @@ -136,6 +150,13 @@ # 包 * 可以在.proto 文件中选择使用 package 说明符 避免 ProtoBuf 消息类型之间的名称冲突(命名空间) package foo.bar; + message Open { ... } + + message Foo { + ... + foo.bar.Open open = 1; + ... + } * 在 Java 里面, 除非在 .proto 文件中显示声明了 option java_package ,否则这个包名会被 Java 直接采用