Main Tutorials

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 Author

author image
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

Subscribe
Notify of
2 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Ranjeet
3 years ago

It will restart the sequence if server got restarted. Right?

sitapati
5 years ago

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