Java 使用同步块预订座位

Java 使用同步块预订座位,java,multithreading,grails,concurrency,gorm,Java,Multithreading,Grails,Concurrency,Gorm,我正在尝试使用以下同步块实现座位预订验证: synchronized(this) { int seatsBooked = GrantAssessment.countByExamSessionAndExamDateBetweenAndIsCancelled(examSession,now,now+1,false) int seatsRemaining = examSession.maxSeat - seatsBooked if(seatsRemaining<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)
}
当我使用浏览器1(不同线程)点击时,它进入synchornized块并指定一个座位。当浏览器2(线程2,几乎同时)进入块时,查询计数由以下代码返回:

     GrantAssessment.countByExamSessionAndExamDateBetweenAndIsCancelled(examSession,now,now+1,false)
相同。但在同步块后,同一线程显示减少值(正确)

因此,即使totalSeat等于1,两个螺纹也会分配阀座


如何处理并发性,以便以同步方式正确计算AvailableSets值。JMS适合这种情况吗?

看起来您使用的是不同的监视器。 例如,即使totalSeat等于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;
        }
    });
}
请注意,
synchronized(this){…}
块中读取/修改的所有变量都不应在没有在同一监视器上同步的情况下从其他地方读取/修改。在其他情况下,它可能导致和


JMS适合这样的场景吗


当然,您可以使用JMS,通过它将预订请求传递给唯一的工作线程。但是对于这个简单的情况,您不需要如此复杂的解决方案。

我可以使用悲观锁定来修复它。我只是在开始时使用examSession=examSession.lock(ID),另一个线程一直等到事务结束。还可以吗?还有,你为什么重复同样的代码两次?可以有很多人同时预订座位。(不仅仅是2个)例如,我在
booktowoseatsinparallel()
函数中重复了两次,您可以在main方法的for循环中轻松运行多次,并确保此代码确实包含错误。悲观锁定是可以的,但它会带来一些额外的开销(通常是不可见的)。因此,这取决于应用程序内部的工作负载。
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;
        }
    });
}
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;
        }
    });
}