先定义一个发号器接口
package com.robert.vesta.service.intf; import com.robert.vesta.service.bean.Id; import java.util.Date; public interface IdService { /** * 发号器的主要API,用来产生唯一ID * @return */ public long genId(); /** * 解读ID,人可识别 * @param id * @return */ public Id expId(long id); /** * 用来伪造某一时间的ID * @param time * @param seq * @return */ public long makeId(long time, long seq); public long makeId(long time, long seq, long machine); public long makeId(long genMethod, long time, long seq, long machine); public long makeId(long type, long genMethod, long time, long seq, long machine); public long makeId(long version, long type, long genMethod, long time, long seq, long machine); /** * 将整形时间翻译成格式化时间 * @param time * @return */ public Date transTime(long time); }
因为有3种同步方式,先给一个抽象类,实现共性.分布式ID由机器号+生产方式+版本号+实现号+时间戳+流水号组成
package com.robert.vesta.service.impl; import com.robert.vesta.service.bean.Id; import com.robert.vesta.service.impl.bean.IdMeta; import com.robert.vesta.service.impl.bean.IdMetaFactory; import com.robert.vesta.service.impl.bean.IdType; import com.robert.vesta.service.impl.converter.IdConverter; import com.robert.vesta.service.impl.converter.IdConverterImpl; import com.robert.vesta.service.impl.provider.MachineIdProvider; import com.robert.vesta.service.impl.timer.SimpleTimer; import com.robert.vesta.service.impl.timer.Timer; import com.robert.vesta.service.intf.IdService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Date; public abstract class AbstractIdServiceImpl implements IdService { protected final Logger log = LoggerFactory.getLogger(this.getClass()); /** * 机器ID */ protected long machineId = -1; /** * 生产方式 */ protected long genMethod = 0; /** * 版本 */ protected long version = 0; /** * 实现类型 */ protected IdType idType; /** * ID元数据 */ protected IdMeta idMeta; /** * 元数据,长整型转换器 */ protected IdConverter idConverter; /** * 机器ID生成器 */ protected MachineIdProvider machineIdProvider; /** * 时间处理类 */ protected Timer timer; public AbstractIdServiceImpl() { idType = IdType.SECONDS; } public AbstractIdServiceImpl(String type) { idType = IdType.parse(type); } public AbstractIdServiceImpl(long type) { idType = IdType.parse(type); } public AbstractIdServiceImpl(IdType type) { idType = type; } /** * 实现共有属性 */ public void init() { if (this.idMeta == null) { setIdMeta(IdMetaFactory.getIdMeta(idType)); } if (this.idConverter == null) { setIdConverter(new IdConverterImpl()); } if (this.timer == null) { setTimer(new SimpleTimer()); } this.timer.init(idMeta, idType); this.machineId = machineIdProvider.getMachineId(); validateMachineId(this.machineId); } /** * 生成ID * @return */ public long genId() { Id id = new Id(); id.setMachine(machineId); id.setGenMethod(genMethod); id.setType(idType.value()); id.setVersion(version); //抽象方法,由子类各自实现,意思就是由不同的方法进行同步 populateId(id); long ret = idConverter.convert(id, this.idMeta); // Use trace because it cause low performance if (log.isTraceEnabled()) log.trace(String.format("Id: %s => %d", id, ret)); return ret; } public void validateMachineId(long machineId){ if (machineId < 0) { log.error("The machine ID is not configured properly (" + machineId + " < 0) so that Vesta Service refuses to start."); throw new IllegalStateException( "The machine ID is not configured properly (" + machineId + " < 0) so that Vesta Service refuses to start."); } else if (machineId >= (1 << this.idMeta.getMachineBits())) { log.error("The machine ID is not configured properly (" + machineId + " >= " + (1 << this.idMeta.getMachineBits()) + ") so that Vesta Service refuses to start."); throw new IllegalStateException("The machine ID is not configured properly (" + machineId + " >= " + (1 << this.idMeta.getMachineBits()) + ") so that Vesta Service refuses to start."); } } protected abstract void populateId(Id id); public Date transTime(final long time) { return timer.transTime(time); } public Id expId(long id) { return idConverter.convert(id, this.idMeta); } public long makeId(long time, long seq) { return makeId(time, seq, machineId); } public long makeId(long time, long seq, long machine) { return makeId(genMethod, time, seq, machine); } public long makeId(long genMethod, long time, long seq, long machine) { return makeId(idType.value(), genMethod, time, seq, machine); } public long makeId(long type, long genMethod, long time, long seq, long machine) { return makeId(version, type, genMethod, time, seq, machine); } public long makeId(long version, long type, long genMethod, long time, long seq, long machine) { Id id = new Id(machine, seq, time, genMethod, type, version); return idConverter.convert(id, this.idMeta); } public void setMachineId(long machineId) { this.machineId = machineId; } public void setGenMethod(long genMethod) { this.genMethod = genMethod; } public void setVersion(long version) { this.version = version; } public void setIdConverter(IdConverter idConverter) { this.idConverter = idConverter; } public void setIdMeta(IdMeta idMeta) { this.idMeta = idMeta; } public void setMachineIdProvider(MachineIdProvider machineIdProvider) { this.machineIdProvider = machineIdProvider; } public void setTimer(Timer timer) { this.timer = timer; } }
实现类,再根据不同的参数进行不同的调用
package com.robert.vesta.service.impl; import com.robert.vesta.service.bean.Id; import com.robert.vesta.service.impl.bean.IdType; import com.robert.vesta.service.impl.populater.AtomicIdPopulator; import com.robert.vesta.service.impl.populater.IdPopulator; import com.robert.vesta.service.impl.populater.LockIdPopulator; import com.robert.vesta.service.impl.populater.SyncIdPopulator; import com.robert.vesta.util.CommonUtils; public class IdServiceImpl extends AbstractIdServiceImpl { /** * 同步锁 */ private static final String SYNC_LOCK_IMPL_KEY = "vesta.sync.lock.impl.key"; /** * 无锁 */ private static final String ATOMIC_IMPL_KEY = "vesta.atomic.impl.key"; protected IdPopulator idPopulator; public IdServiceImpl() { super(); } public IdServiceImpl(String type) { super(type); } public IdServiceImpl(long type) { super(type); } public IdServiceImpl(IdType type) { super(type); } @Override public void init() { super.init(); initPopulator(); } /** * 根据不同的方式调用不同的同步机制 */ public void initPopulator() { if (idPopulator != null){ log.info("The " + idPopulator.getClass().getCanonicalName() + " is used."); } else if (CommonUtils.isPropKeyOn(SYNC_LOCK_IMPL_KEY)) { log.info("The SyncIdPopulator is used."); idPopulator = new SyncIdPopulator(); } else if (CommonUtils.isPropKeyOn(ATOMIC_IMPL_KEY)) { log.info("The AtomicIdPopulator is used."); idPopulator = new AtomicIdPopulator(); } else { log.info("The default LockIdPopulator is used."); idPopulator = new LockIdPopulator(); } } protected void populateId(Id id) { idPopulator.populateId(timer, id, idMeta); } public void setIdPopulator(IdPopulator idPopulator) { this.idPopulator = idPopulator; } }
因为无锁跟重入锁或者synchronized不同,所以会有接口,一个抽象类
package com.robert.vesta.service.impl.populater; import com.robert.vesta.service.bean.Id; import com.robert.vesta.service.impl.bean.IdMeta; import com.robert.vesta.service.impl.timer.Timer; public interface IdPopulator { /** * 同秒内产生流水号 * @param timer * @param id * @param idMeta */ void populateId(Timer timer, Id id, IdMeta idMeta); /** * 不同秒内重置 */ void reset(); }
package com.robert.vesta.service.impl.populater; import com.robert.vesta.service.bean.Id; import com.robert.vesta.service.impl.bean.IdMeta; import com.robert.vesta.service.impl.timer.Timer; public abstract class BasePopulator implements IdPopulator { /** * 流水号 */ protected long sequence = 0; /** * 上一次的时间 */ protected long lastTimestamp = -1; public BasePopulator() { super(); } /** * 产生流水ID的算法 * @param timer * @param id * @param idMeta */ public void populateId(Timer timer, Id id, IdMeta idMeta) { long timestamp = timer.genTime(); timer.validateTimestamp(lastTimestamp, timestamp); if (timestamp == lastTimestamp) { sequence++; sequence &= idMeta.getSeqBitsMask(); if (sequence == 0) { timestamp = timer.tillNextTimeUnit(lastTimestamp); } } else { lastTimestamp = timestamp; sequence = 0; } id.setSeq(sequence); id.setTime(timestamp); } public void reset() { this.sequence = 0; this.lastTimestamp = -1; } }
其实前面只是铺垫------------------------------
package com.robert.vesta.service.impl.populater; import com.robert.vesta.service.bean.Id; import com.robert.vesta.service.impl.bean.IdMeta; import com.robert.vesta.service.impl.timer.Timer; public class SyncIdPopulator extends BasePopulator { public SyncIdPopulator() { super(); } public synchronized void populateId(Timer timer, Id id, IdMeta idMeta) { super.populateId(timer, id, idMeta); } }
package com.robert.vesta.service.impl.populater; import com.robert.vesta.service.bean.Id; import com.robert.vesta.service.impl.bean.IdMeta; import com.robert.vesta.service.impl.timer.Timer; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockIdPopulator extends BasePopulator { private Lock lock = new ReentrantLock(); public LockIdPopulator() { super(); } public void populateId(Timer timer, Id id, IdMeta idMeta) { lock.lock(); try { super.populateId(timer, id, idMeta); } finally { lock.unlock(); } } }
以上是两个同步方法的实现,都继承于抽象类
原子类无锁只实现接口,不继承于抽象类
package com.robert.vesta.service.impl.populater; import com.robert.vesta.service.bean.Id; import com.robert.vesta.service.impl.bean.IdMeta; import com.robert.vesta.service.impl.timer.Timer; import java.util.concurrent.atomic.AtomicReference; public class AtomicIdPopulator implements IdPopulator { class Variant { private long sequence = 0; private long lastTimestamp = -1; } private AtomicReference<Variant> variant = new AtomicReference<Variant>(new Variant()); public AtomicIdPopulator() { super(); } public void populateId(Timer timer, Id id, IdMeta idMeta) { Variant varOld, varNew; long timestamp, sequence; while (true) { // Save the old variant varOld = variant.get(); // populate the current variant timestamp = timer.genTime(); timer.validateTimestamp(varOld.lastTimestamp, timestamp); sequence = varOld.sequence; if (timestamp == varOld.lastTimestamp) { sequence++; sequence &= idMeta.getSeqBitsMask(); if (sequence == 0) { timestamp = timer.tillNextTimeUnit(varOld.lastTimestamp); } } else { sequence = 0; } // Assign the current variant by the atomic tools varNew = new Variant(); varNew.sequence = sequence; varNew.lastTimestamp = timestamp; if (variant.compareAndSet(varOld, varNew)) { id.setSeq(sequence); id.setTime(timestamp); break; } } } public void reset() { variant = new AtomicReference<Variant>(new Variant()); } }