2015-12-30 61 views
1

我試圖使用來實現座位預訂驗證一個同步塊是這樣的:座位預訂使用同步塊

synchronized(this) { 
    int seatsBooked = GrantAssessment.countByExamSessionAndExamDateBetweenAndIsCancelled(examSession,now,now+1,false) 
    int seatsRemaining = examSession.maxSeat - seatsBooked 
    if(seatsRemaining<1){ 
     throw new CustomValidationException("All seats booked...") 
    } 

    // assign assessment which increases countByExam... query count by 1 
    grantAssessment = assignAssessment(examCommerce,examSession,examDate,identificationType,idNumber) 
} 

assignAssessment()方法的代碼如下:

def assignAssessment(ExamCommerce examCommerce, ExamSession examSession,Date examDate,IdentificationType identificationType,String idNumber) { 
    ................. 
    examSession.addToGrantAssessmentList(grantAssessment) 
    .............................. 
    grantAssessment.save(failOnError: true,flush: true) 
    examSession.save(failOnError: true,flush: true) 
    return grantAssessment 
} 

當我打使用瀏覽器1(不同的線程)它進入synchornized塊並分配一個座位。當瀏覽器2(線程2,幾乎同時)進入查詢計數通過下面的代碼返回的塊:

 GrantAssessment.countByExamSessionAndExamDateBetweenAndIsCancelled(examSession,now,now+1,false) 

被same.But同一線程表示同步塊後還原值(正確的)。

由於這個原因,兩個線程分配即使totalSeat等於1

如何處理併發使得availableSeats值應該被以同步的方式正確地計算出的座位。 JMS是否適合這種情況?

+0

http://tutorials.jenkov.com/java-concurrency/synchronized.html – Ahmed

回答

2

好像你正在使用不同的顯示器。 例如下面可以像你描述both the threads assigns the seat even if totalSeat is equal to 1.

private static ExecutorService executorService = Executors.newFixedThreadPool(2); 

boolean bookTwoSeatsInParallel() { 
    Future<Integer> res1 = executorService.submit(new Callable<Integer>() { 
     @Override 
     public Integer call() throws Exception { 
      synchronized(this) { 
       //your seat booking code which returns seat num or whatever 
      } 
      return -1; 
     } 
    }); 

    Future<Integer> res2 = executorService.submit(new Callable<Integer>() { 
     @Override 
     public Integer call() throws Exception { 
      synchronized(this) { 
       //your seat booking code which returns seat num or whatever 
      } 
      return -1; 
     } 
    }); 
} 

res1.get().equals(res2.get())可能是真的導致相同的狀態。這個例子有點多餘,但它顯示了不同的線程在試圖獲得有效的同步狀態時使用不同的監視器的情況。
爲了解決這個問題,你應該在同一監視器同步,這樣

private static ExecutorService executorService = Executors.newFixedThreadPool(2); 
private final Object bookingMonitor = new Object(); 

boolean bookTwoSeatsInParallel() { 
    Future<Integer> res1 = executorService.submit(new Callable<Integer>() { 
     @Override 
     public Integer call() throws Exception { 
      synchronized(bookingMonitor) { 
       //your seat booking code which returns seat num or whatever 
      } 
      return -1; 
     } 
    }); 

    Future<Integer> res2 = executorService.submit(new Callable<Integer>() { 
     @Override 
     public Integer call() throws Exception { 
      synchronized(bookingMonitor) { 
       //your seat booking code which returns seat num or whatever 
      } 
      return -1; 
     } 
    }); 
} 

請注意,你讀/修改synchronized(this) {...}塊內部不應該讀/從別的地方修改而不同步的所有變量相同的顯示器在其他情況下,它可能會導致Thread InterferenceMemory Consistency Errors


是對這樣的場景JMS OK?

當然,您可以使用JMS,通過它傳遞預訂請求到唯一的工作線程。但對於這種簡單情況,您不需要這樣複雜的解決方案。

+0

我能夠使用悲觀鎖定來修復它。我只是在開始時使用examSession = ExamSession.lock(ID),另一個線程等待事務結束。可以嗎? –

+0

另外,你爲什麼重複兩次相同的代碼。 ?可以有很多人同時預訂一個座位(不只是2) –

+0

我在'bookTwoSeatsInParallel()'函數中重複了兩次,例如,您可以在main方法的for循環中輕鬆地運行多次,並確保這代碼確實包含錯誤。悲觀鎖定是好的,但它帶來了一些額外的開銷(通常不明顯)。所以它取決於應用程序內的工作負載。 – dezhik