Java Sequence Generator examples

An example to show you how to create a thread safe sequence generator.

1. SequenceGenerator

SequenceGenerator.java

package com.mkyong.concurrency.examples.sequence.generator;

public interface SequenceGenerator {
    long getNext();
}

1.1 First try, read, add, write the value directly. Below method is not thread safe, multiple threads may get the same value at the same time.

UnSafeSequenceGenerator.java

package com.mkyong.concurrency.examples.sequence.generator;

public class UnSafeSequenceGenerator implements SequenceGenerator {

    private long value = 1;

    @Override
    public long getNext() {
        return value++;
    }

}

1.2 To fix this, make the getNext() as a synchronized method.

SyncSequenceGenerator.java

package com.mkyong.concurrency.examples.sequence.generator;

public class SyncSequenceGenerator implements SequenceGenerator {

    private long value = 1;

    @Override
    public synchronized long getNext() {
        return value++;
    }
}

1.3 The better solution is using the concurrent.atomic classes, for example AtomicLong

AtomicSequenceGenerator.java

package com.mkyong.concurrency.examples.sequence.generator;

import java.util.concurrent.atomic.AtomicLong;

public class AtomicSequenceGenerator implements SequenceGenerator {

    private AtomicLong value = new AtomicLong(1);

    @Override
    public long getNext() {
        return value.getAndIncrement();
    }
}

2. Concurrent Access

Simulate a concurrent access environment to test the above sequence generator.

2.1. A Callable task to access the sequence 10 time.

PrintSequenceCallable.java

package com.mkyong.concurrency.examples.sequence;

import com.mkyong.concurrency.examples.sequence.generator.SequenceGenerator;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

public class PrintSequenceCallable implements Callable<List<Long>> {

    private SequenceGenerator sequenceGenerator;

    public PrintSequenceCallable(SequenceGenerator sequenceGenerator) {
        this.sequenceGenerator = sequenceGenerator;
    }

    @Override
    public List<Long> call() throws Exception {

        List<Long> ids = new ArrayList<>();

        for (int i = 1; i <= 10; i++) {
            Thread.sleep(100); //take a nap
            ids.add(sequenceGenerator.getNext());
        }

        return ids;

    };

}

2.2 Start 3 threads to test the sequence generator.

Main.java

package com.mkyong.concurrency.examples.sequence;

import com.mkyong.concurrency.examples.sequence.generator.SequenceGenerator;
import com.mkyong.concurrency.examples.sequence.generator.UnSafeSequenceGenerator;

import java.util.List;
import java.util.concurrent.*;

public class Main {

    public static void main(String[] args) {

        SequenceGenerator sequenceGenerator = new UnSafeSequenceGenerator();
        //SequenceGenerator sequenceGenerator = new SyncSequenceGenerator();
        //SequenceGenerator sequenceGenerator = new AtomicSequenceGenerator();

        ExecutorService executor = Executors.newCachedThreadPool();

        try {

			// simulate 3 threads concurrent access the sequence generator
            Callable<List<Long>> task1 = new PrintSequenceCallable(sequenceGenerator);
            Callable<List<Long>> task2 = new PrintSequenceCallable(sequenceGenerator);
            Callable<List<Long>> task3 = new PrintSequenceCallable(sequenceGenerator);

            Future f1 = executor.submit(task1);
            Future f2 = executor.submit(task2);
            Future f3 = executor.submit(task3);

            System.out.println(f1.get());
            System.out.println(f2.get());
            System.out.println(f3.get());

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }

    }

}

Output

2.2.1 UnSafeSequenceGenerator - Aka race condition, multiple threads is getting the same value, this is not what we want.


[3, 5, 6, 7, 8, 10, 12, 15, 16, 17]
[2, 4, 6, 7, 8, 9, 13, 15, 16, 17]
[1, 4, 6, 7, 8, 11, 14, 15, 16, 17]

2.2.2 SyncSequenceGenerator - Thread safe.


[3, 6, 8, 10, 14, 17, 21, 24, 27, 29]
[1, 4, 9, 12, 15, 18, 20, 22, 25, 30]
[2, 5, 7, 11, 13, 16, 19, 23, 26, 28]

2.2.3 AtomicSequenceGenerator - Thread safe.


[3, 6, 8, 12, 13, 18, 19, 22, 27, 29]
[2, 5, 7, 10, 14, 17, 20, 24, 26, 30]
[1, 4, 9, 11, 15, 16, 21, 23, 25, 28]

Both synchronized and AtomicLong are able to create a thread safe sequence generator. However, the synchronized method is expensive, it will increase the performance cost, the recommended way is using the concurrent.atomic classes like AtomicLong, the atomic classes are designed for concurrent use.

Download Source Code

References

  1. Synchronized Methods
  2. Atomic Variables
  3. Why are synchronize expensive in Java?
  4. Race Condition

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

avatar
1 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
sitapati Recent comment authors
newest oldest most voted
sitapati
Guest
sitapati

Hi In Multi-threaded environment Numbers are unique,but not in sequence. It should be in sequence in multi threaded environment too . how can you achieve that. for ex: 1,2,3,4,5,6….100