Java 共享对象的等待/通知导致主线程挂起

Java 共享对象的等待/通知导致主线程挂起,java,multithreading,quartz-scheduler,Java,Multithreading,Quartz Scheduler,首先,让我承认,我是一名经验丰富的Java开发人员,能够意识到等待/通知问题,但一直没有得到线索,这就是为什么当我们陷入某些问题而忽略了显而易见的问题时,我觉得更多的人的输入会有所帮助。我正在编写一个测试来验证Quartz作业类,我按照以下示例进行测试: public class SchedulerTest { private static final Object LOCK = new Object(); @Test public void sh

首先,让我承认,我是一名经验丰富的Java开发人员,能够意识到等待/通知问题,但一直没有得到线索,这就是为什么当我们陷入某些问题而忽略了显而易见的问题时,我觉得更多的人的输入会有所帮助。我正在编写一个测试来验证Quartz作业类,我按照以下示例进行测试:

   public class SchedulerTest {
       private static final Object LOCK = new Object();
       @Test
       public void shouldValidateSomethingInJob() {
           Object[] paramsForTesting = ...
           SchedulerFactory sf = new StdSchedulerFactory();
           Scheduler scheduler = sf.getScheduler();
           ...
           CustomJobListenerSupport jobListener =
                new CustomJobListenerSupport(LOCK, paramsForTesting);
           scheduler.getListenerManager().addJobListener(jobListener,
                KeyMatcher.keyEquals(jobKey));
           scheduler.start();
           //        synchronized (LOCK) {
           //            // Wait for scheduler to end to avoid DB rollback before that
           //            LOCK.wait();
           //        }
        }

    private static class CustomJobListenerSupport extends JobListenerSupport        
    {
        private final Object lock;

        public CustomJobListenerSupport(Object lock, Object ... paramsForTesting) {
            ...;
            this.lock = lock;
        }

        @Override
        public String getName() {
            return "TestJobListener";
        }

        @Override
        public void jobWasExecuted(JobExecutionContext context,
                                   JobExecutionException jobException) {
            if (isNotBlank(jobException.getMessage())) {
                try {
                    cleanup(context.getScheduler());
                } catch (SchedulerException e) {
                    logger.error(e);
                }
                throw new RuntimeException(jobException);
            }

            performAssertions();
            try {
                cleanup(context.getScheduler());
            } catch (SchedulerException e) {
                throw new RuntimeException(e);
            }
        }

        private void performAssertions() {
            // Some assertions
        }

        @SneakyThrows
        private void cleanup(Scheduler scheduler) throws SchedulerException {
            scheduler.clear();
            scheduler.shutdown();
            System.out.println("\nLock in cleanup: "+lock);
            synchronized (lock) {
                lock.notify();
            }
        }
    }
  }
现在,在注释掉等待代码后,测试完成但失败,因为DB更改在调度程序完成之前回滚,如果我等待,主线程似乎至少会挂起,这花费了很长时间,似乎没有结束,我无法确定作业是否仍在运行,因为Junit没有编写包含日志语句的HTML报告。调试语句表明这两个类使用同一个锁对象。同意有比使用普通对象来锁定更好的选项,但我不熟悉ReentrantLock之类的类,所以希望稍后尝试

任何指示都会有很大帮助

谢谢,
Paddy

使用调试器,检查是否调用了清理方法,以及是否执行了lock.notify。它可能应该在finally块中的某个位置,以确保它始终被执行,不管发生什么。可能在等待之前调用notify。添加检查是否已调用notify的标志。您好,我对其进行了调试,发现奇怪的是,当我注释等待部分时,程序到达作业调用的服务类,或者换句话说,作业运行,但当我等待时,它从未触发。调度程序应该是一个单独的线程,为什么在主线程进入等待队列时从不调用它?这令人费解