java syncronized

CHR·2024년 4월 28일
0

기능 개발 중
1. 데이터를 리스트에 넣기
2. 리스트의 길이를 계산하기
두 가지 기능을 하는 메소드를 구현했다.

이 메소드가 실행될 때 2번 작업에서 리스트의 길이는 정확히 1번 작업을 마친 직후의 길이여야 했는데, 여러 클라이언트가 이 메소드를 호출하면서 1번 작업과 2번 작업의 사이에 다른 클라이언트가 호출한 메소드의 1번 작업이 실행되어 리스트의 길이를 정확히 세지 못 하는 일이 생길 수도 있을 것 같았다.

그래서 이 메소드에 syncronized를 사용하여 스레드 동기화 처리를 했다.
작성한 코드는 다음과 같다.

    public synchronized SubmitStatus addAnswer(Long playerId, String playerAnswer) {
        playerAnswers.add(Answer.builder()
                .user_id(playerId)
                .user(playerAnswer)
                .build());
        return checkSubmitStatus();
    }

스레드 동기화

스레드 동기화는 멀티스레드 환경에서 여러 스레드가 하나의 공유자원에 동시에 접근하지 못하도록 막는 것이다. 공유데이터가 사용되어 동기화가 필요한 부분을 임계영역(critical section)이라고 부르며, 자바에서는 이 임계영역에 synchronized 키워드를 사용하여 여러 스레드가 동시에 접근하는 것을 금지함으로써 동기화를 할 수 있다. 

synchronized 사용 방법

synchronized 키워드는 동기화가 필요한 메소드나 코드 블럭 앞에 사용한다. synchronized로 지정된 임계영역은 한 스레드가 이 영역에 접근하여 사용할 때 lock을 걸어 다른 스레드가 접근할 수 없게 한다. 해당 스레드가 이 임계영역의 코드를 다 실행한 후 벗어나게 되면 unlock 상태가 되고, 이후 대기하고 있던 다른 스레드가 이 임계영역에 접근하여 다시 lock을 걸고 사용할 수 있게 된다. 
lock은 해당 객체당 하나씩 존재하며, synchronized로 설정된 임계영역은 lock 권한을 얻은 하나의 객체만이 독점적으로 사용하게 된다. 

1. 메소드에 적용
내가 작성한 코드와 같은 방식이다.

    public synchronized SubmitStatus addAnswer(Long playerId, String playerAnswer) {
        playerAnswers.add(Answer.builder()
                .user_id(playerId)
                .user(playerAnswer)
                .build());
        return checkSubmitStatus();
    }

2. 코드 블럭에 적용
필요한 부분에만 this를 사용하여 적용하면 된다.

    public SubmitStatus addAnswer(Long playerId, String playerAnswer) {
        synchronized(this) {
            playerAnswers.add(Answer.builder()
                    .user_id(playerId)
                    .user(playerAnswer)
                    .build());
            SubmitStatus submitStatus = checkSubmitStatus();
        }
        return submitStatus;
    }

(참고: https://kadosholy.tistory.com/123)

profile
🍷

0개의 댓글

관련 채용 정보