用于唯一ID的Java中的序列生成器

时间:2014-03-14 22:22:34

标签: java multithreading sequence

我打算编写一个将要使用的序列生成器 在post期间生成我的REST资源实现类 唯一身份。由于每个帖子请求都由单独的线程处理, 我使变量volatile和方法同步。  我没有选择使用序列或其他东西 传统的RDBMS提供。

public class SequenceGen {
    volatile static int n = 0;  
    public synchronized int nextNum(){
        return n++;
    }   
}

这是我到目前为止所做的,并计划创建一个变量 我的REST实现中的SequenceGen。我的实际问题是 它在某个地方破了?我测试了两个线程,我没有看到 重复的任何价值。

3 个答案:

答案 0 :(得分:23)

它会起作用,但AtomicInteger是内置类型,非常适合您的用例。

AtomicInteger seq = new AtomicInteger();
int nextVal = seq.incrementAndGet();

答案 1 :(得分:1)

如果您可以使用String代替int,而不是UUID,则可能需要考虑使用// the value of uuid will be something like '03c9a439-fba6-41e1-a18a-4c542c12e6a8' String uuid = java.util.UUID.randomUUID().toString() (通用唯一标识符)。非常容易使用,顾名思义,它们是独一无二的。以下是如何生成一个的示例:

UUID

int还提供了比{{1}}更高的安全性,因为对于整数,您可以通过简单地将1添加到您的请求ID来猜测下一个请求ID,但是UUID不是连续的,并且任何人都可能猜到其他任何人#39;的请求ID非常小。

答案 2 :(得分:1)

您可以利用java.util.prefs.Preferences将序列生成器的当前状态保留在磁盘上,稍后再次使用。

(另外,您可能想要使用多个序列生成器)

即。

import java.lang.ref.SoftReference;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.prefs.Preferences;

public final class SequenceGenerator {

    private static final Preferences PREFS = Preferences.userNodeForPackage(SequenceGenerator.class);
    private static final AtomicLong SEQ_ID = new AtomicLong(Integer.parseInt(PREFS.get("seq_id", "1")));
    private static final Map<Long, SoftReference<SequenceGenerator>> GENERATORS = new ConcurrentHashMap<>();
    private static final SequenceGenerator DEF_GENERATOR = new SequenceGenerator(0L, Long.parseLong(PREFS.get("seq_0", "1")));

    static {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            GENERATORS.values().stream()
                    .map(SoftReference::get)
                    .filter(seq -> seq != null && seq.isPersistOnExit())
                    .forEach(SequenceGenerator::persist);
            if (DEF_GENERATOR.isPersistOnExit()) {
                DEF_GENERATOR.persist();
            }
            PREFS.put("seq_id", SEQ_ID.toString());
        }));
    }

    private final long sequenceId;
    private final AtomicLong counter;
    private final AtomicBoolean persistOnExit = new AtomicBoolean();

    private SequenceGenerator(long sequenceId, long initialValue) {
        this.sequenceId = sequenceId;
        counter = new AtomicLong(initialValue);
    }

    public long nextId() {
        return counter.getAndIncrement();
    }

    public long currentId() {
        return counter.get();
    }

    public long getSequenceId() {
        return sequenceId;
    }

    public boolean isPersistOnExit() {
        return persistOnExit.get();
    }

    public void setPersistOnExit(boolean persistOnExit) {
        this.persistOnExit.set(persistOnExit);
    }

    public void persist() {
        PREFS.put("seq_" + sequenceId, counter.toString());
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        GENERATORS.remove(sequenceId);
        if (persistOnExit.get()) {
            persist();
        }
    }

    @Override
    public int hashCode() {
        return Long.hashCode(sequenceId);
    }

    @Override
    public boolean equals(Object obj) {
        return obj == this || obj != null && obj instanceof SequenceGenerator && sequenceId == ((SequenceGenerator) obj).sequenceId;
    }

    @Override
    public String toString() {
        return "{" +
                "counter=" + counter +
                ", seq=" + sequenceId +
                '}';
    }

    public static SequenceGenerator getDefault() {
        return DEF_GENERATOR;
    }

    public static SequenceGenerator get(long sequenceId) {
        if (sequenceId < 0) {
            throw new IllegalArgumentException("(sequenceId = " + sequenceId + ") < 0");
        }
        if (sequenceId == 0) {
            return DEF_GENERATOR;
        }
        SoftReference<SequenceGenerator> r = GENERATORS.computeIfAbsent(sequenceId, sid -> {
            try {
                return new SoftReference<>(new SequenceGenerator(sid, Long.parseLong(PREFS.get("seq_" + sid, null))));
            } catch (Throwable t) {
                return null;
            }
        });
        return r == null ? null : r.get();
    }

    public static SequenceGenerator create() {
        return create(1);
    }

    public static SequenceGenerator create(long initialValue) {
        long sequenceId = SEQ_ID.getAndIncrement();
        SequenceGenerator seq = new SequenceGenerator(sequenceId, Long.parseLong(PREFS.get("seq_" + sequenceId, "" + initialValue)));
        GENERATORS.put(sequenceId, new SoftReference<>(seq));
        return seq;
    }

}