在十进制中,个位的1代表10⁰=1,十位的1代表10¹=10,百位的1代表10²=100,所以:123=1×10²+2×10¹+3×10⁰
同样道理,在二进制中,个位的1代表2⁰=1,十位的1代表2¹=2,百位的1代表2²=4,所以:(A3A2A1A0)₂=A3×2³+A2×2²+A1×2¹+A0×2⁰
如果二进制和十进制数出现在同一个等式中,为了区别我们用(A3A2A1A0)₂这种形式表示A3A2A1A0是二进制数,每个数字只能是0或1,其它没有套括号加下标的数仍表示十进制数。对于(A3A2A1A0)₂这样一个二进制数,最左边的A3位称为最高位(MSB,Most Significant Bit),最右边的A0位称为最低位(LSB,Least Significant Bit)。以后我们遵循这样的惯例: LSB称为第0位而不是第1位,所以如果一个数是32位的,则MSB是第31位 。上式就是从二进制到十进制的换算公式。
下面来看十进制怎么换算成二进制。我们知道
13=1×2³+1×2²+0×2¹+1×2⁰ 所以13换算成二进制应该是(1101)₂。问题是怎么把13分解成等号右边的形式呢?注意到等号右边可以写成
13=(((0×2+1₃)×2+1₂)×2+0₁)×2+1₀
我们将13反复除以2取余数就可以提取出上式中的1101四个数字,为了让读者更容易看清楚是哪个1和哪个0,上式和下式中对应的数字都加了下标:
13÷2=6...1₀ 6÷2=3...0₁ 3÷2=1...1₂ 1÷2=0...1₃
把这四步得到的余数按相反的顺序排列就是13的二进制表示,因此这种方法称为除二反序取余法。
计算机用二进制表示数,程序员也必须习惯使用二进制,但二进制写起来太啰嗦了,所以通常将二进制数分成每三位一组或者每四位一组,每组用一个数字表示。比如把(10110010)₂从最低位开始每三位分成一组,10、110、010,然后把每组写成一个十进制数字,就是(262)₈,这样每一位数字的取值范围是0~7,逢八进一,称为八进制(Octal)。类似地,把(10110010)₂分成每四位一组,1011、0010,然后把每组写成一个数字,这个数的低位是2,高位已经大于9了,我们规定用字母A~F表示10~15,这个数可以写成(B2)₁₆,每一位数字的取值范围是0~F,逢十六进一,称为十六进制(Hexadecimal)。所以,八进制和十六进制是程序员为了书写二进制方便而发明的简便写法,好比草书和正楷的关系一样。
整数在计算机中用二进制的位来表示,C语言提供一些运算符可以直接操作整数中的位,称为位运算。
移位运算符(Bitwise Shift)包括左移<<和右移>>。左移将一个整数的各二进制位全部左移若干位,例如0xcfffffff3<<2得到0x3fffffcc:
Java 平台都是有符号整数,所以上述图一操作在Java中符号位发生了变化值由(-805306381)变为(1073741772)
在一定的取值范围内,将一个整数左移1位相当于乘以2。比如二进制11(十进制3)左移一位变成110,就是6,再左移一位变成1100,就是12。读者可以自己验证这条规律对有符号数和无符号数都成立,对负数也成立。当然,如果左移改变了最高位(符号位),那么结果肯定不是乘以2了,所以我加了个前提“ 在一定的取值范围内 ”。由于计算机做移位比做乘法快得多,编译器可以利用这一点做优化,比如看到源代码中有i * 8,可以编译成移位指令而不是乘法指令。
当操作数是无符号数时,右移运算的规则和左移类似,例如0xcffffff3>>2得到0x33fffffc:
Java 平台执行结果:值由-805306381 变成 -201326596 仍然保留负数的符号位,相当于除以4
最低两位的11被移出去了,最高两位又补了两个0,其它位依次右移两位。和左移类似,移动的位数也必须小于左操作数的总位数,否则结果是Undefined。在一定的取值范围内,将一个整数右移1位相当于除以2,小数部分截掉。
当操作数是有符号数时,右移运算的规则比较复杂:
综上所述,由于类型转换和移位等问题,用有符号数做位运算是很不方便的,所以, 建议只对无符号数做位运算,以减少出错的可能 。
如果要对一个整数中的某些位进行操作,怎样表示这些位在整数中的位置呢?可以用掩码(Mask)来表示。比如掩码 0x0000ff00 表示对一个32位整数的8~15位进行操作,举例如下。
1、取出8~15位。
unsigned int a, b, mask = 0x0000ff00; a = 0x12345678; b = (a & mask) >> 8; /* 0x00000056 */ 复制代码
2、将8~15位清0。
unsigned int a, b, mask = 0x0000ff00; a = 0x12345678; b = a & ~mask; /* 0x12340078 */ 复制代码
3、将8~15位置1。
unsigned int a, b, mask = 0x0000ff00; a = 0x12345678; b = a | mask; /* 0x1234ff78 */ 复制代码
shrding-jdbc默认的实现:
/** * 默认的主键生成器. * * <p> * 长度为64bit,从高位到低位依次为 * </p> * * <pre> * 1bit 符号位 * 41bits 时间偏移量从2016年11月1日零点到现在的毫秒数 * 10bits 工作进程Id * 12bits 同一个毫秒内的自增量 * </pre> * * <p> * 工作进程Id获取优先级: 系统变量{@code sharding-jdbc.default.key.generator.worker.id} 大于 环境变量{@code SHARDING_JDBC_DEFAULT_KEY_GENERATOR_WORKER_ID} * ,另外可以调用@{@code DefaultKeyGenerator.setWorkerId}进行设置 * </p> * * @author gaohongtao */ @Getter @Slf4j public final class DefaultKeyGenerator implements KeyGenerator { public static final long EPOCH; public static final String WORKER_ID_PROPERTY_KEY = "sharding-jdbc.default.key.generator.worker.id"; public static final String WORKER_ID_ENV_KEY = "SHARDING_JDBC_DEFAULT_KEY_GENERATOR_WORKER_ID"; private static final long SEQUENCE_BITS = 12L; private static final long WORKER_ID_BITS = 10L; private static final long SEQUENCE_MASK = (1 << SEQUENCE_BITS) - 1; private static final long WORKER_ID_LEFT_SHIFT_BITS = SEQUENCE_BITS; private static final long TIMESTAMP_LEFT_SHIFT_BITS = WORKER_ID_LEFT_SHIFT_BITS + WORKER_ID_BITS; private static final long WORKER_ID_MAX_VALUE = 1L << WORKER_ID_BITS; @Setter private static TimeService timeService = new TimeService(); @Getter private static long workerId; static { Calendar calendar = Calendar.getInstance(); calendar.set(2016, Calendar.NOVEMBER, 1); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); EPOCH = calendar.getTimeInMillis(); initWorkerId(); } private long sequence; private long lastTime; public static void initWorkerId() { String workerId = System.getProperty(WORKER_ID_PROPERTY_KEY); if (!Strings.isNullOrEmpty(workerId)) { setWorkerId(Long.valueOf(workerId)); return; } workerId = System.getenv(WORKER_ID_ENV_KEY); if (Strings.isNullOrEmpty(workerId)) { return; } setWorkerId(Long.valueOf(workerId)); } /** * 设置工作进程Id. * * @param workerId 工作进程Id */ public static void setWorkerId(final long workerId) { Preconditions.checkArgument(workerId >= 0L && workerId < WORKER_ID_MAX_VALUE); DefaultKeyGenerator.workerId = workerId; } /** * 生成Id. * * @return 返回@{@link Long}类型的Id */ @Override public synchronized Number generateKey() { long currentMillis = timeService.getCurrentMillis(); Preconditions.checkState(lastTime <= currentMillis, "Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds", lastTime, currentMillis); if (lastTime == currentMillis) { if (0L == (sequence = ++sequence & SEQUENCE_MASK)) { currentMillis = waitUntilNextTime(currentMillis); } } else { sequence = 0; } lastTime = currentMillis; if (log.isDebugEnabled()) { log.debug("{}-{}-{}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(lastTime)), workerId, sequence); } return ((currentMillis - EPOCH) << TIMESTAMP_LEFT_SHIFT_BITS) | (workerId << WORKER_ID_LEFT_SHIFT_BITS) | sequence; } private long waitUntilNextTime(final long lastTime) { long time = timeService.getCurrentMillis(); while (time <= lastTime) { time = timeService.getCurrentMillis(); } return time; } } 复制代码