본문 바로가기

Back/Java

[Java/SpringBoot] 멀티 스레드 & static 테스트

static은 클래스에 고정된다.

static멤버(static변수, static메서드) = 정적멤버

인스턴스에 소속되지 않고, 클래스에 고정되어 있다.

static 영역의 메모리에 저장되기 때문에 가비지 콜렉터의 관리 대상이 아니다.

 

테스트1. 두개의 instance에서 static 사용

plus, minus 메서드를 사용해서 static변수 `balance` 의 값이 어떻게 변하는지 관찰

단일 스레드에서 실행

// application 실행

@Slf4j
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);

        StaticTestService instance1 = new StaticTestService();
        log.info("plus 30,000 : {}", instance1.plus(30000));
        log.info("minus 5,000 : {}", instance1.minus(5000));

        StaticTestService instance2 = new StaticTestService();
        log.info("instance2 balance : {}", instance2.getBalance());
        
        /** 
         * 결과
         * plus 30,000 : 30000
         * minus 5,000 : 25000
         * instance2 balance : 25000
         */
    }

}
@Service
public class StaticTestService {
    private static int balance = 0;

    public int getBalance() {
        return balance;
    }

    public int plus(int value) {
        balance += value;
        return getBalance();
    }

    public int minus(int value) {
        balance -= value;
        return getBalance();
    }
}

 

 

멀티스레드에서도 static 변수

테스트2. plus, minus API 호출시 static 변수의 상태

- spring boot 기본 멀티 스레드 사용 (controller로 api호출)

- 여러번의 호출에도 `balance` 값이 계속 유지되는지 관찰

@Slf4j
@RestController
public class StaticTestController {
    
    StaticTestService service = new StaticTestService();

    @GetMapping(value = "/balance")
    public int getBalance(){
        return service.getBalance();
    }

    @GetMapping(value = "/plus/1000")
    public int plus1000(){
        int balance = service.plus(1000);
        log.info("[service id : {}] plus 1,000 : {}", StaticTestService.id , balance);
        return balance;
    }

    @GetMapping(value = "/minus/500")
    public int minus500(){
        int balance = service.minus(500);
        log.info("[service id : {}] minus 500 : {}", StaticTestService.id , balance);
        return balance;
    }
}
/**
 * 결과
 * service instance가 계속 새로 생성되지만 balance는 유지된다. (instance uuid로 확인)
 * 서버가 재시작되고, application이 초기화되면 balance도 초기화 된다.
 */
/**
 * log
 * 2022-01-02 16:23:14.348  INFO 45661 --- [nio-8081-exec-7] c.g.s.controller.StaticTestController    : [service id : e786bf2d-339b-4627-bda6-ad3d6115ec48] plus 1,000 : 1000
 * 2022-01-02 16:23:15.092  INFO 45661 --- [nio-8081-exec-8] c.g.s.controller.StaticTestController    : [service id : e786bf2d-339b-4627-bda6-ad3d6115ec48] plus 1,000 : 2000
 * 2022-01-02 16:23:17.271  INFO 45661 --- [nio-8081-exec-9] c.g.s.controller.StaticTestController    : [service id : e786bf2d-339b-4627-bda6-ad3d6115ec48] minus 500 : 1500
 * 2022-01-02 16:23:22.132  INFO 45661 --- [io-8081-exec-10] c.g.s.controller.StaticTestController    : [service id : e786bf2d-339b-4627-bda6-ad3d6115ec48] plus 1,000 : 2500
 * 2022-01-02 16:23:24.612  INFO 45661 --- [nio-8081-exec-1] c.g.s.controller.StaticTestController    : [service id : e786bf2d-339b-4627-bda6-ad3d6115ec48] minus 500 : 2000
 *
 * 서버 재시작 후, uuid 변경
 * 2022-01-02 16:25:37.904  INFO 45689 --- [nio-8081-exec-2] c.g.s.controller.StaticTestController    : [service id : af378220-6177-4606-813e-562caac4752d] plus 1,000 : 1000
 * 2022-01-02 16:25:38.620  INFO 45689 --- [nio-8081-exec-3] c.g.s.controller.StaticTestController    : [service id : af378220-6177-4606-813e-562caac4752d] plus 1,000 : 2000
 * 2022-01-02 16:25:40.720  INFO 45689 --- [nio-8081-exec-4] c.g.s.controller.StaticTestController    : [service id : af378220-6177-4606-813e-562caac4752d] minus 500 : 1500
 */
@Service
public class StaticTestService {
    private static int balance = 0;
    public static final UUID id = UUID.randomUUID();

    public int getBalance() {
        return balance;
    }

    public int plus(int value) {
        balance += value;
        return getBalance();
    }

    public int minus(int value) {
        balance -= value;
        return getBalance();
    }
}