Məqalələr

Java’da AtomicInteger nümunəsi

java-atomicinteger
Written by Mushfiq Mammadov

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.

About the author

Mushfiq Mammadov

Leave a Comment

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.