AtomicInteger
Java`ya hələ 1.5-ci versiyada gəlməsinə baxmayaraq mən onun faydalılığını hələ təzə-təzə kəşf etməyə başlamışam. Asinxron sorğularda sayğac (counter) kimi istifadə etmək üçün çox əlverişlidir, əlavə iş görməyə – metodu yaxud bloku synchronized
etməyə yaxud volatile
açar sözündən istifadə etməyə ehtiyac qalmır.
AtomicInteger
ilə bağlı kiçik bir kod nümunəsi hazırlayacam və orada göstərməyə çalışacam ki, biz bunu necə istifadə edə bilərik. İndi isə kodun nə iş görəcəyinə qısaca baxaq.
Tutaq ki, web servisimiz var, stress test etmək istəyirik. Bunun üçün servisə “bulk” sorğu göndərəcəyik, məsələn ardıcıl 10 min sorğu. Bu sorğuların servisə eyni anda göndərilməsini təmin etmək üçün “thread pool” istifadə edəcəyik. Və əsas məsələ qarşımızda belə bir məhdudiyyət var ki, biz servisə hər dəfə təkrarlanmayan id (unique id) göndərməliyik. Bunun üçün sayğac (counter) yaradacağıq və bu məqsədlə də AtomicInteger
istifadə edəcəyik.
Bəs AtomicInteger
bizə nə üçün lazımdır, adi increment istifadə edə bilmərik?
Bizim göndərdiyimiz sorğular asinxron olduğu üçün eyni millisaniyədə də baş verə bilər və əgər biz sayğac üçün Java`da adi increment istifadə etsək (++counter
) id dəyərləri təkrarlana bilər. AtomicInteger
classında isə “thread safe” məsələsi nəzərə alındığından, əlavə heç nə istifadən etmədən bu class vasitəsilə çox rahat şəkildə təkrarlanmayan dəyərlər əldə edə bilərik. AtomicInteger
-in faydalı metodları çoxdur, amma biz qeyd etdiyimiz məqsəd üçün incrementAndGet()
metodunu istifadə edəcəyik.
Əlavə olaraq biz AtomicInteger
-dən göndərdiyimiz bütün sorğulara (request) cavab (response) alıb-almadığımızı yoxlamaq üçün də istifadə edə bilərik. Bütün sorğular asinxron şəkildə icra edildiyindən “thread safe” olmayan dəyişənlə biz bunu düzgün hesablamaya bilərik. Amma AtomicInteger
-lə bunu çox rahat və dəqiq şəkildə edə bilərik. Nümunəyə baxaq.
package az.mm.atomicinteger; import java.io.*; import java.nio.file.Files; import java.nio.file.Paths; import java.time.LocalTime; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** * * @author MM <[email protected]> */ public class AtomicIntegerExample { private final int poolSize = 100; private final ExecutorService execService = Executors.newFixedThreadPool(poolSize); private final int numberOfRequest = 10_000; private final AtomicInteger numberOfResponse = new AtomicInteger(); private final AtomicInteger counter = new AtomicInteger(getLastNumber()); private final AtomicBoolean exit = new AtomicBoolean(); private final String fixedValue = "888888"; public static void main(String[] args) { AtomicIntegerExample exp = new AtomicIntegerExample(); exp.start(); } private void start() { new EndingCheck().start(); for (int i = 0; i < numberOfRequest; i++) { execService.execute(sendRequest(i+1)); } } private class EndingCheck extends Thread { @Override public void run() { while (!exit.get()) { try { Thread.sleep(100); } catch (InterruptedException e) { } int completed = numberOfResponse.get(); System.out.printf("\n%s/%s request are completed. \n\n", completed, numberOfRequest); if (completed == numberOfRequest) close(); } } } private Runnable sendRequest(int i) { return () -> { String id = fixedValue + counter.incrementAndGet(); // we need unique id System.out.printf("Request number: %5s | OrderId: [%s] | %s\n", i, id, LocalTime.now()); //you can call your service here numberOfResponse.incrementAndGet(); }; } private int getLastNumber() { int number = 100_000; try { String fileName = "src/main/resources/number.txt"; String lastNumber = new String(Files.readAllBytes(Paths.get(fileName))); number = Integer.parseInt(lastNumber); } catch (IOException ex) { ex.printStackTrace(); } System.out.println("Last number from file: " + number); return number; } private void saveLastNumber() { try(PrintWriter writer = new PrintWriter("src/main/resources/number.txt"); ) { int lastNumber = counter.get(); writer.print(lastNumber); System.out.println("saved last number: " + lastNumber); } catch (FileNotFoundException ex) { System.err.println("number.txt file not found"); } } private void close() { execService.shutdown(); exit.set(true); saveLastNumber(); } }
Github link:
https://github.com/mmushfiq/AtomicIntegerExample
P.S. Məqalənin üz şəkli www.journaldev.com saytına məxsusdur.