복붙노트

[SPRING] 스프링 싱글 톤 스레드 안전성

SPRING

스프링 싱글 톤 스레드 안전성

종속성 삽입을 통해 내 웹 응용 프로그램에 주입되는 아래에 정의 된 Java 클래스가있는 경우

public AccountDao
{
   private NamedParameterJdbcTemplate njt;
   private List<Account> accounts;

   public AccountDao(Datasource ds)
   {
       this.njt = new NamedParameterJdbcTemplate(ds);
       refreshAccounts();
   }

   /*called at creation, and then via API calls to inform service new users have 
     been added to the database by a separate program*/
   public void refreshAccounts()
   {
      this.accounts = /*call to database to get list of accounts*/
   }

   //called by every request to web service
   public boolean isActiveAccount(String accountId)
   {
       Account a = map.get(accountId);
       return a == null ? false : a.isActive();
   }
}

스레드 안전에 대해 우려하고 있습니다. Spring 프레임 워크는 하나의 요청이 목록에서 읽고 다른 요청에 의해 현재 업데이트되고있는 경우를 처리하지 못합니까? 이전에 다른 응용 프로그램에서 읽기 / 쓰기 잠금을 사용했지만 이전에는 위와 같은 경우를 생각한 적이 없습니다.

데이터베이스 부하를 줄일 수 있도록 콩을 싱글 톤으로 사용할 계획이었습니다.

그건 그렇고, 이것은 아래 질문의 후속 조치입니다 :

데이터베이스로드를 줄이기위한 Java 메모리 스토리지 - 안전?

편집하다:

이렇게이 코드는이 문제를 해결할 것이다 :

/*called at creation, and then via API calls to inform service new users have 
         been added to the database by a separate program*/
       public void refreshAccounts()
       {
          //java.util.concurrent.locks.Lock
          final Lock w = lock.writeLock();
          w.lock();
          try{
               this.accounts = /*call to database to get list of accounts*/
          }
          finally{
             w.unlock();
          }
       }

       //called by every request to web service
       public boolean isActiveAccount(String accountId)
       {
           final Lock r = lock.readLock();
           r.lock();

           try{
               Account a = map.get(accountId);
           }
           finally{
               r.unlock();
           }
           return a == null ? false : a.isActive();
       }

해결법

  1. ==============================

    1.Spring 프레임 워크는 싱글 톤 빈의 다중 스레드 동작과 관련하여 아무 것도하지 않습니다. 싱글 톤 빈의 동시성 문제와 스레드 안전성을 처리하는 것은 개발자의 책임입니다.

    Spring 프레임 워크는 싱글 톤 빈의 다중 스레드 동작과 관련하여 아무 것도하지 않습니다. 싱글 톤 빈의 동시성 문제와 스레드 안전성을 처리하는 것은 개발자의 책임입니다.

    나는 아래 기사를 읽을 것을 제안 할 것이다 : Spring Singleton, Request, Session Beans and Thread Safety

  2. ==============================

    2.당신은 나의 초기 대답에 대한 명확한 설명을 요구할 수있었습니다. Spring은 빈에 대한 액세스를 동기화하지 않습니다. 기본 범위 (싱글 톤)에 Bean이 있으면 해당 Bean에 대해 단일 객체 만 존재하며 모든 동시 요청은 해당 객체에 액세스하므로 스레드 안전에 대한 객체가 필요합니다.

    당신은 나의 초기 대답에 대한 명확한 설명을 요구할 수있었습니다. Spring은 빈에 대한 액세스를 동기화하지 않습니다. 기본 범위 (싱글 톤)에 Bean이 있으면 해당 Bean에 대해 단일 객체 만 존재하며 모든 동시 요청은 해당 객체에 액세스하므로 스레드 안전에 대한 객체가 필요합니다.

    대부분의 스프링 빈은 변경 가능한 상태가 없으므로 스레드 안전성이 거의 없습니다. bean은 변경 가능한 상태를 가지므로 다른 스레드가 현재 어셈블하고있는 계정 목록을 어떤 스레드도 보지 않도록해야합니다.

    가장 쉬운 방법은 계정 필드를 휘발성으로 만드는 것입니다. 그것은 당신이 필드를 채운 후에 필드에 새로운리스트를 할당한다고 가정합니다.

    private volatile List<Accounts> accounts;
    
  3. ==============================

    3.싱글 톤 (singleton)과 비동기 (non-synchronized) 인 스프링은 isActiveAccount와 refreshAccounts를 동시에 호출하는 스레드를 허용합니다. 따라서이 클래스는 스레드로부터 안전하지 않으므로 데이터베이스 부하를 감소시키지 않습니다.

    싱글 톤 (singleton)과 비동기 (non-synchronized) 인 스프링은 isActiveAccount와 refreshAccounts를 동시에 호출하는 스레드를 허용합니다. 따라서이 클래스는 스레드로부터 안전하지 않으므로 데이터베이스 부하를 감소시키지 않습니다.

  4. ==============================

    4.우리는 그러한 많은 메타 데이터를 가지고 있으며 약 11 개의 노드가 실행 중이다. 각 앱 노드마다 이러한 데이터에 대한 정적지도가 있으므로 하나의 인스턴스 만, 시작시 DB에서 시작하여 매일 피크 시간대에 한 번 또는 지원 담당자가 트리거 할 때 사용합니다. Interval 간단한 http 게시 기반 API를 사용하여 실시간으로 업데이트해야하는 일부 데이터에 대해 1 노드에서 다른 노드로 업데이트를 보냅니다.

    우리는 그러한 많은 메타 데이터를 가지고 있으며 약 11 개의 노드가 실행 중이다. 각 앱 노드마다 이러한 데이터에 대한 정적지도가 있으므로 하나의 인스턴스 만, 시작시 DB에서 시작하여 매일 피크 시간대에 한 번 또는 지원 담당자가 트리거 할 때 사용합니다. Interval 간단한 http 게시 기반 API를 사용하여 실시간으로 업데이트해야하는 일부 데이터에 대해 1 노드에서 다른 노드로 업데이트를 보냅니다.

    public AccountDao
    {
       private static List<Account> accounts;
       private static List<String> activeAccounts;
       private NamedParameterJdbcTemplate njt;
    
       static {
           try{
            refreshAccounts();
           }catch(Exception e){
            //log but do not throw. any uncaught exceptions in static means your class is un-usable
           }
       }
    
    
       public AccountDao(Datasource ds)
       {
           this.njt = new NamedParameterJdbcTemplate(ds);
           //refreshAccounts();
       }
    
       /*called at creation, and then via API calls to inform service new users have 
         been added to the database by a separate program*/
       public void refreshAccounts()
       {
          this.accounts = /*call to database to get list of accounts*/
       }
    
       public void addAccount(Account acEditedOrAdded)
       {
          //add or reove from map onr row
          //can be called from this node or other node
          //meaning if you have 2 nodes, keep IP port of each or use a internal web service or the like to tell 
          //node B when a account id added or changed in node A ...
       }   
    
       //called by every request to web service
       public static boolean isActiveAccount(String accountId)
       {
           Account a = map.get(accountId);
           return a == null ? false : a.isActive();
       }
    }
    
  5. from https://stackoverflow.com/questions/15396608/spring-singleton-thread-safety by cc-by-sa and MIT license