Skip to content

Latest commit

 

History

26 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

자바 스프링에서 동시성 제어: synchronized vs ReentrantLock

1. 서론

자바 스프링 애플리케이션에서 다중 스레드 환경에서의 동시성 제어는 필수적입니다. 이를 위해 자바는 synchronized 키워드와 ReentrantLock 클래스를 제공하며, 각기 다른 특징을 가지고 있습니다. 본 문서에서는 synchronizedReentrantLock의 장단점을 비교하고, 각각의 사용 시나리오에서 어떤 방법이 적합한지 분석합니다.

2. 동시성 제어의 필요성

동시성 제어는 여러 스레드가 동일한 리소스에 접근할 때 데이터의 일관성과 무결성을 유지하기 위한 필수적인 기법입니다. 특히, 자바 스프링 애플리케이션은 웹 요청에 대해 다중 스레드로 처리되는 경우가 많아 동시성 제어의 중요성이 매우 큽니다.

3. synchronizedReentrantLock의 기본 개념

  • synchronized: 자바의 기본적인 락 기법으로, 블록이나 메서드 단위로 사용되며, 락을 자동으로 획득하고 해제합니다.
  • ReentrantLock: java.util.concurrent.locks 패키지에서 제공하는 락 클래스입니다. 명시적으로 락을 획득(lock())하고 해제(unlock())해야 하며, 더 유연한 동시성 제어 기능을 제공합니다.

4. synchronizedReentrantLock의 장단점 비교

비교 항목 synchronized ReentrantLock
사용의 간편함 매우 간단하게 사용 가능, 블록/메서드에 키워드 추가만 필요 명시적으로 락을 획득하고 해제해야 하며 더 복잡함
재진입성 재진입 가능 재진입 가능
공정성 기본적으로 비공정 모드, 순서 보장 없음 공정 모드 설정 가능
타임아웃 지원하지 않음 tryLock() 메서드를 통해 타임아웃 설정 가능
인터럽트 가능성 지원하지 않음 lockInterruptibly()로 인터럽트 처리 가능
성능 간단한 동시성 제어에 더 나은 성능 상황에 따라 다르며, 공정성 설정 시 성능 저하 가능
디버깅 용이성 비교적 단순하여 디버깅이 용이함 복잡하여 디버깅이 어려울 수 있음

5. DB에서의 동시성 제어

데이터베이스에서 동시성 제어는 트랜잭션이 여러 스레드 또는 프로세스에 의해 동시에 실행될 때 데이터 무결성을 유지하는 데 필수적입니다. 주로 사용되는 기법은 다음과 같습니다:

  1. 낙관적 락킹 (Optimistic Locking):

    • 트랜잭션이 데이터베이스에서 데이터를 읽을 때 다른 트랜잭션이 해당 데이터를 수정하지 않았다는 가정하에 작업을 진행합니다.
    • 주로 버전 필드를 사용하여 데이터의 변경 여부를 확인하고, 충돌이 발생하면 트랜잭션을 롤백합니다.
  2. 비관적 락킹 (Pessimistic Locking):

    • 데이터에 대한 접근이 발생하기 전에 해당 데이터에 락을 걸어 다른 트랜잭션이 접근하지 못하도록 합니다.
    • 데이터의 충돌이 예상되는 상황에서 주로 사용되며, 대기 시간이 길어질 수 있습니다.
  3. Isolation Levels:

    • DBMS는 트랜잭션의 격리 수준을 설정하여 서로 다른 트랜잭션 간의 영향을 제어합니다. 일반적으로 사용되는 격리 수준은 다음과 같습니다:
      • READ UNCOMMITTED
      • READ COMMITTED
      • REPEATABLE READ
      • SERIALIZABLE

이러한 방법을 통해 데이터베이스에서의 동시성 제어를 구현할 수 있으며, 특정 요구사항에 따라 적절한 방법을 선택하는 것이 중요합니다.

6. 사용 사례에 따른 선택

  1. 간단한 동시성 제어가 필요한 경우:

    • synchronized 사용이 적합. 단순한 메서드 내 동기화.
  2. 복잡한 락 관리가 필요한 경우:

    • ReentrantLock 사용이 적합. 타임아웃, 공정성, 인터럽트 처리가 필요할 때.
    lock.lock();
    try {
        // critical section
    } finally {
        lock.unlock();
    }
  3. 데이터 무결성을 보장해야 하는 경우: -데이터베이스의 트랜잭션 및 락 메커니즘을 활용하는 것이 적합. ACID 속성을 보장하며, 동시성 충돌을 방지하기 위해 SELECT FOR UPDATE 쿼리 등을 사용할 수 있습니다.

    BEGIN;
    SELECT * FROM user_points WHERE user_id = ? FOR UPDATE;
    UPDATE user_points SET points = points + ? WHERE user_id = ?;
    COMMIT;
  4. 높은 동시성을 처리해야 하는 경우: -데이터베이스에서 Optimistic Locking 또는 Pessimistic Locking을 고려. Optimistic Locking은 충돌이 적은 경우에 유용하며, Pessimistic Locking은 충돌 가능성이 높은 경우에 데이터를 잠가 안전성을 보장합니다. 예를 들어, JPA에서 @Version 애노테이션을 사용하여 낙관적 락을 구현할 수 있습니다.

    @Entity
    public class UserPoint {
      @Id
      private Long id;
    
      @Version
      private Long version;
    
      private Long points;
    }
    
  5. 성능과 무결성을 동시에 고려해야 하는 경우: -코드에서의 동시성 제어와 DB에서의 동시성 제어를 혼합하여 사용할 수 있습니다. 비즈니스 로직에서 동기화 필요성을 관리하고, 데이터베이스에서 추가적인 무결성 보장을 수행하여 최적의 성능과 안정성을 확보할 수 있습니다.

  6. 락 대기 시간이 중요한 경우: -ReentrantLocktryLock()을 사용하여 타임아웃 설정이 가능.

  7. 공정성이 중요한 경우: -ReentrantLock의 공정 모드를 사용하여 스레드 순서를 보장.

  8. 인터럽트 가능한 락이 필요한 경우: -ReentrantLocklockInterruptibly()로 인터럽트 처리 가능.

  9. 재귀적 메서드 호출이 필요한 경우: -재진입 특성을 제공하는 두 방식 모두 가능하지만, ReentrantLock이 복잡한 시나리오에 적합.

7. 성능 고려 사항

-synchronized: -간단한 락 상황에서 성능이 우수하며, 자원 접근이 빈번하지 않을 때 적합.

-ReentrantLock: -공정성 설정, 타임아웃 등의 기능을 제공하지만, 복잡한 락 관리에서 성능 손실이 있을 수 있음.

8. ReentratLock 선택 이유

  1. DB환경이 아니기에 transationJPA를 이용한 방법은 제외
  2. 더 나은 성능: -Synchronized는 너무 많이 사용했을 때에 성능저하를 발생
  3. 공정성: -공정성이란? 공정한 lock을 사용할 경우 | 경쟁 발생 -> 가장 오랫동안 기다린 쓰레드에게 lock을 제공 -Synchronized와 달리 ReentratLock은 공정성 설정이 가능
  4. ConcurrentHashMap: -ReentrantLockConcurrentHashMap을 함께 사용하면 스레드 안전성을 유지하면서도 성능을 최적화할 수 있는 유연한 동시성 관리가 가능 / 각 도구의 장점을 활용하여 복잡한 동시성 요구 사항을 효과적으로 처리 가능

9. 결론

-간단한 동기화는 synchronized가 더 간편하고 성능적으로 유리.

-그러나 타임아웃, 공정성, 인터럽트 처리 등이 필요한 경우에는 ReentrantLock을 사용하는 것이 적합.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages