3

I need to generate an unique number of 32 bits in Java. I need to return the number as Java int, which is required by the interface. Can you please share some ideas on this?

The number will be used as MySQL PK and several threads could be generating their own unique id at same time. (Sorry it is decided not to use MySQL incremental id)

I tried UUID class but it seems the data it generates has more bits than I can use.

I found this but not sure if it works:

    // seems no way to get int
    UUID id = UUID.randomUUID();
    System.out.println(id);

    // not working either?
    java.rmi.server.UID uid = new java.rmi.server.UID();
    System.out.println(uid.toString());

    // the one i am using
    SecureRandom prng = SecureRandom.getInstance("SHA1PRNG");
    prng.setSeed(System.currentTimeMillis());
    int ret = prng.nextInt();
    System.out.println(ret);
X.M.
  • 941
  • 3
  • 14
  • 22
  • possible duplicate of [generating UUID but only for 8 characters](http://stackoverflow.com/questions/4267475/generating-uuid-but-only-for-8-characters) – Stephen C Dec 10 '10 at 04:44
  • 1
    The MySQL `bigint` type is 64 bit and would have less chance of collision. This would be better if you can change the database schema. – Joshua Martell Dec 10 '10 at 04:52

3 Answers3

5

How "unique" are you wanting? In short, what is the collision domain? If you are dealing with thousands of keys then Random.nextInt() does exactly what you want relative to what you tried with version 4 UUIDs (UUID v4 generates 128 random bits).

If you need something with a less chance of collision then you need to have a globally incremented integer but there is much care to be taken here such as keeping state between JVM startups. For that you should look into AtomicIntegers.

Andrew White
  • 52,720
  • 19
  • 113
  • 137
  • I am more clear for the requirements; it seems there isn't much need to be 'very unique'. We decided to use time-based values and handle races ourselves. However this discussion is useful and I appreciate all of you. – X.M. Dec 10 '10 at 07:32
1

The SecureRandom approach is fine, but don't set the seed on it. It will choose it's own seed in a (presumably) secure manner.

You could also use a UUID and just discard the bits you don't need, e.g.

int key = (int)UUID.randomUUID().getLeastSignificantBits();

EDIT: You should also be aware that the SecureRandom is significantly slower than Random. Since you're not doing crypto here, why not use Random?

Cameron Skinner
  • 51,692
  • 2
  • 65
  • 86
  • 1
    No, you couldn't. http://blogs.msdn.com/b/oldnewthing/archive/2008/06/27/8659071.aspx – dan04 Dec 10 '10 at 04:36
  • The source for the UUID class shows that it generates 128 random bits, then tinkers with a few of them. The changed bits are all in the most significant set, so taking only the least significant bits should work fine. Still, it's less work to just use a `Random`. – Cameron Skinner Dec 10 '10 at 04:41
  • @dan04: For the UUID implementation you cite you're correct, but for the Java UUID implementation (at least the Sun java 6 implementation) my answer will work fine. – Cameron Skinner Dec 10 '10 at 04:42
0

I think you can use a 32-bit hash function. details are given in the following tutorial http://www.concentric.net/~ttwang/tech/inthash.htm

private static int hash(int key){

          key = ~key + (key << 15); // key = (key << 15) - key - 1;
          key = key ^ (key >>> 12);
          key = key + (key << 2);
          key = key ^ (key >>> 4);
          key = key * 2057; // key = (key + (key << 3)) + (key << 11);
          key = key ^ (key >>> 16);
          return key;

    }
Upul Bandara
  • 5,973
  • 4
  • 37
  • 60