我打算编写一个将要使用的序列生成器 在post期间生成我的REST资源实现类 唯一身份。由于每个帖子请求都由单独的线程处理, 我使变量volatile和方法同步。 我没有选择使用序列或其他东西 传统的RDBMS提供。
public class SequenceGen {
volatile static int n = 0;
public synchronized int nextNum(){
return n++;
}
}
这是我到目前为止所做的,并计划创建一个变量 我的REST实现中的SequenceGen。我的实际问题是 它在某个地方破了?我测试了两个线程,我没有看到 重复的任何价值。
答案 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;
}
}