Skip to content

SimpleIdGenerator is not thread safe, neither it is documented to be #25485

@wind57

Description

@wind57

I have a small miss-understanding about SimpleIdGenerator, that is a fairly trivial class:

public class SimpleIdGenerator implements IdGenerator {

	private final AtomicLong mostSigBits = new AtomicLong(0);

	private final AtomicLong leastSigBits = new AtomicLong(0);


	@Override
	public UUID generateId() {
		long leastSigBits = this.leastSigBits.incrementAndGet();
		if (leastSigBits == 0) {
			this.mostSigBits.incrementAndGet();
		}
		return new UUID(this.mostSigBits.get(), leastSigBits);
	}

}

The presence of AtomicLong hints into the fact that this is a thread-safe continuous incremented UUID, but it's not the case:

long leastSigBits = this.leastSigBits.incrementAndGet();
if (leastSigBits == 0) {

For the sake of the discussion let's suppose that currently leastSigBits holds a -1 (it has been incremented quite a lot, yes).

ThreadA does long leastSigBits = this.leastSigBits.incrementAndGet();, so it puts the value into 0 (-1 + 1 = 0); but before it does the check if (leastSigBits == 0), ThreadB did long leastSigBits = this.leastSigBits.incrementAndGet(); too, now on a value that is 0, so it put the value in 1. ThreadA does the check and sees a value of 1, that if statement is not entered and a such a duplicate UUID.

This is very far stretched and I have doubts it has ever impacted any users as for this to happen they would need to generate all the long range of IDs, which is highly highly improbable. Still, this code is wrong.

If this is suppose to provide thread-safe variant :

  • document it as such
  • fix the code

if this isn't supposed to be thread safe, simply dropping the un-necessary AtomicLong (with it's volatile overhead) is going to be a big performance gain.

Either way, I would be more than glad to fix this, if someone tells me the path I should be taking. Thank you.

Metadata

Metadata

Assignees

Labels

in: messagingIssues in messaging modules (jms, messaging)type: taskA general task

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions