仅限一台服务器
关于多个表主键的生成,在不建议扩展主键长度的前提下,通过对时间戳加锁来解决主键重复问题
import org.apache.commons.lang.StringUtils;
import com.fto.sql.UniqueTimestamp;
public class Test {
public static UniqueTimestamp UT = new UniqueTimestamp();
public static String generateId() {
synchronized (UT) {
return StringUtils.leftPad(Long.toHexString(UT.getUniqueTimestamp()).toUpperCase(), 16, '0');
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(generateId());
}
}).start();
}
}
}
从100个线程同时执行的结果来看,没有重复,但是目前还有几个疑问:
1.会不会出现两次执行时间差小于时间戳最小单位?
2.虽然可能解决了问题,但是效率是否降低影响整体?
3.回到问题,除了此方法,是否可以生成16位唯一值?
补充下
package com.fto.sql;
public class UniqueTimestamp
{
public static final char PRECISION_MILLISECOND = 'S';
public static final char PRECISION_SECOND = 's';
public static final char PRECISION_MINUTE = 'm';
private char precision = 'S';
private long ts = -1L;
public UniqueTimestamp() {}
public UniqueTimestamp(char prec)
{
if ((prec != 'S') && (prec != 's') && (prec != 'm')) {
throw new IllegalArgumentException("Illegal argument for UniqueTimestamp. Only 'S', 's','m' can be used.");
}
this.precision = prec;
}
public synchronized long getUniqueTimestamp()
{
if (this.ts == -1L)
{
this.ts = getCurrentTimeValue();
}
else
{
long t = getCurrentTimeValue();
if (t <= this.ts) {
this.ts += 1L;
} else {
this.ts = t;
}
}
return getReturnValue(this.ts);
}
private long getCurrentTimeValue()
{
long ts;
switch (this.precision)
{
case 'S':
default:
ts = System.currentTimeMillis();
break;
case 's':
ts = System.currentTimeMillis() / 1000L;
break;
case 'm':
ts = System.currentTimeMillis() / 60000L;
}
return ts;
}
private long getReturnValue(long ts)
{
switch (this.precision)
{
case 'S':
default:
return ts;
case 's':
return ts * 1000L;
}
return ts * 60000L;
}
}