Java Sequence Generator examples
An example to show you how to create a thread safe sequence generator.
1. SequenceGenerator
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.
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.
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
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.
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.
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.
References
From:一号门
Previous:Java Semaphore examples
COMMENTS