2016-08-10 2 views
1

나는 다음과 같은 코드가 있습니다자바 : 동기화 스레드에 실패

for (int iThreadCounter = 1; iThreadCounter <= CONNECTIONS_NUM; iThreadCounter++){ 
    WorkThread wt = new WorkThread(iThreadCounter); 
    new Thread(wt).start(); 
    m_arrWorkThreadsToCreate.add(wt); 
} 

그 스레드가 다음 코드 호출

int res = m_spLegJoin.call(m_workTread, m_workTread.getConfId()); 

그리고이 LegJoinSp 클래스 내부의 호출 방법 :

public class LegJoinSp extends ConnEventSp { 

    private static final int _LEG_JOIN_ACTION_CODE = 22; 
    private static int m_nLegId = Integer.valueOf(IniUtils.getIniValue("General", "LEG_ID_START")); 
    private final Lock m_lock = new ReentrantLock(); 

    public int call(WorkThread a_workThread, String a_sConfId) { 

     synchronized (this) { 

      //m_lock.lock(); 
      m_nLegId++; 

      boolean bPass = false; 

      Log4jWrapper.writeLog(LogLevelEnum.DEBUG, "LegJoinSp - call", "a_workThread = " + a_workThread.getThreadId() + " a_sConfId = " + a_sConfId); 

      if (super.call(a_workThread, a_sConfId, _LEG_JOIN_ACTION_CODE, "" + m_nLegId) == 0) { 

       bPass = true; 

      } else { 
       bPass = false; 
      } 

      //m_lock.unlock(); 

      if (bPass) { 

       Log4jWrapper.writeLog(LogLevelEnum.DEBUG, "LegJoinSp - call", "a_workThread = " + a_workThread.getThreadId() + " a_sConfId = " + a_sConfId + " returned leg id " + m_nLegId); 

       return m_nLegId; 
      } else { 

       return -1; 
      } 
     } 

    } 

    public Lock getLock() { 
     return m_lock; 
    } 

} 

이 call() 메소드를 호출하는 스레드가 두 개 있습니다. m_nLegId는 당신은 내가 함께 방법을 잠글 시도 볼 수 있듯이 100 으로 시작됩니다 모두

synchronized(this) 

m_lock.lock() and m_lock.unlock() 

문제입니다 처음 경우에 (bPass)를 얻을 때 내부 코드는 102를 m_nLegId 값으로 내 로그에 씁니다. 그러나 나는 10130이기를 기대한다. m_nLegId ++; 성명. 첫 번째 스레드 실행을 위해 동기화 블록이 끝나기 전에 두 번째 스레드가 코드 내부로 들어가는 것 같습니다.

어떻게 해결할 수 있습니까?

은 (당신이 에 잠금을 적용되는) 것은 당신이 모든 스레드가 새로운 객체를 만드는 것입니다,하지만 당신은 잠금을 적용하는 방식은 동일 객체에 적용하면

+1

'LegJoinSp' 클래스가 주로 사용되는 방식으로 코드를 추가해야합니다. 보이는 동작에 대한 가장 쉬운 설명은 두 개의 서로 다른 개체를 사용한다는 것입니다. 그러면 개인 잠금을 동기화하거나 잠그면 아무 일도하지 않게됩니다. – Kiskae

+0

@Kiskae 두 가지 방법을 사용하고 있지 않습니다. 나는 그것들을 따로 따로 시험해 보았다. 동기화 된 한 번 및 잠금 개체 한 번. – dushkin

+1

은 MCVE http : // stackoverflow 규칙에 따라 스레드를 시작하는 코드를 표시합니다.위한 COM/도움말/mcve –

답변

2

나에게 당신의 버그는 m_nLegIdstatic field이라는 사실과 관련이 있으며 클래스의 현재 인스턴스에 대한 액세스를 동기화하여 필드의 동시 수정을 올바르게 방지하지 못하게하려고합니다.

나는

synchronized (this) { 

오히려

synchronized (LegJoinSp.class) { 

NB 수 있어야 의미 : 당신은 단지 카운터를해야 할 경우, 당신의 필드 대신 지능에 대한 AtomicInteger을 사용하는 것이 좋습니다.

+0

빙고! 고맙습니다! – dushkin

1

감사드립니다.
클래스 수준에서 잠금을 적용하려는 경우 정적 개체를 만들고 달성하려는 목적을 달성 할 수있는 해당 개체에 잠금을 적용 할 수 있습니다 (주석을 기반으로 올바르게 문제를 이해 한 경우)

+0

zstring 주셔서 감사합니다. 너의 대답은 니콜라스의 대답과 매우 비슷하다. 그래서 나는 그것을지지했지만 해결책으로 둘 다 표시 할 수는 없습니다. – dushkin