Хобрук: Ваш путь к мастерству в программировании

Java ExecutorService и ThreadPoolExecutor

Я испытываю странную проблему. Я пытаюсь использовать модель производителя/потребителя. Пожалуйста, предложите, если я сделал что-то не так. Когда я использую ExecutorService с фиксированным потоком 4, я никогда не получаю никаких исключений, и программа запускается, НО когда я использую ThreadPoolExecutor , это дает мне исключение. Не могу понять в чем ошибка! Пожалуйста, порекомендуйте!

код ExecutorService:

ArrayBlockingQueue<BillableList> list =new ArrayBlockingQueue<BillableList>(2);
ThreadFactory threadFactory = Executors.defaultThreadFactory();
 ExecutorService threadPool = Executors.newFixedThreadPool(4, threadFactory);

  threadPool.execute(new BillingConsu(network,"consumer->"+Thread.currentThread(), list)); 
  threadPool.execute(new BillingConsu(network,"consumer->"+Thread.currentThread(), list));
  threadPool.execute(new BillingConsu(network,"consumer->"+Thread.currentThread(), list));

Future producerStatus = threadPool.submit(new BillProdu(this.network,"Producer", list)); 
producerStatus.get();
threadPool.shutdown(); 

 while (!threadPool.isTerminated()) {
 threadPool.shutdown();
 threadPool.awaitTermination(10, TimeUnit.SECONDS);
 }

Код ThreadPoolExecutor:

ArrayBlockingQueue<BillableList> list =new ArrayBlockingQueue<BillableList>(4);
BlockingQueue<Runnable> worksQueue = new ArrayBlockingQueue<Runnable>(100);
RejectedExecutionHandler executionHandler = new MyRejectedExecutionHandelerImpl();
ThreadFactory threadFactory = Executors.defaultThreadFactory();
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5,5, 10, 
 TimeUnit.SECONDS, worksQueue,threadFactory, executionHandler);
 Future producerStatus = threadPool.submit(new BillProdu(this.network,"Producer", list)); 
 producerStatus.get(); 

  threadPool.execute(new BillingConsu(network,"consumer 1", list)); 
  threadPool.execute(new BillingConsu(network,"consumer 2", list));
  threadPool.execute(new BillingConsu(network,"consumer 3", list));
  threadPool.execute(new BillingConsu(network,"consumer 4", list));
  threadPool.shutdown(); 

             while (!threadPool.isTerminated()) {
              threadPool.shutdown();
                threadPool.awaitTermination(10, TimeUnit.SECONDS);
           }

Исключение при запуске ThreadPoolExecutor :

Exception in thread "pool-1-thread-2" java.lang.ExceptionInInitializerError
    at org.apache.axis.utils.Messages.<clinit>(Messages.java:36)
    at org.apache.axis.configuration.EngineConfigurationFactoryFinder$1.run    (EngineConfigurationFactoryFinder.java:141)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.axis.configuration.EngineConfigurationFactoryFinder.newFactory    (EngineConfigurationFactoryFinder.java:113)
    at org.apache.axis.configuration.EngineConfigurationFactoryFinder.newFactory    (EngineConfigurationFactoryFinder.java:160)
    at org.apache.axis.client.Service.getEngineConfiguration(Service.java:813)
    at org.apache.axis.client.Service.getAxisClient(Service.java:104)
    at org.apache.axis.client.Service.<init>(Service.java:113)
    at org.tempuri.OnlineBillingLocator.<init>(OnlineBillingLocator.java:28)
    at com.mixem.sdc.sms.StsSmsConnection.<init>(StsSmsConnection.java:40)
    at BillingConsu.doStsBilling(BillingConsu.java:202)
    at BillingConsu.run(BillingConsu.java:60)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.NullPointerException
    at java.io.FileOutputStream.<init>(FileOutputStream.java:172)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:102)
    at org.apache.log4j.FileAppender.setFile(FileAppender.java:290)
    at LogFileWriter.append(LogFileWriter.java:45)
    at org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:251)
    at org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders    (AppenderAttachableImpl.java:66)
    at org.apache.log4j.Category.callAppenders(Category.java:206)
    at org.apache.log4j.Category.forcedLog(Category.java:391)
    at org.apache.log4j.Category.log(Category.java:856)
    at org.apache.commons.logging.impl.Log4JLogger.debug(Log4JLogger.java:177)
    at org.apache.axis.i18n.ProjectResourceBundle.getBundle(ProjectResourceBundle.java:264)
    at org.apache.axis.i18n.MessagesConstants.<clinit>(MessagesConstants.java:32) 

Файл свойств Log4J

log4j.rootLogger = DEBUG, fileout
log4j.appender.fileout = LogFileWriter
log4j.appender.fileout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c - %m%n
log4j.appender.fileout.layout = org.apache.log4j.PatternLayout
log4j.appender.fileout.File = /logs/billinglogs.log

Код добавления LogFileWriter

@Override
public void append(LoggingEvent event) {
try {
setFile(appendLevelToFileName((String) MDC.get(ORIG_LOG_FILE_NAME),
event.getLevel().toString()), fileAppend, bufferedIO,bufferSize);
} catch (IOException ie) {
errorHandler.error("Error occured while setting file for the log level "+ event.getLevel(), ie,
ErrorCode.FILE_OPEN_FAILURE);
    }
super.append(event);
}

MDC помещает код в LogFileWriter

@Override
public void activateOptions() {
MDC.put(ORIG_LOG_FILE_NAME, fileName);
super.activateOptions();
 }

  • Похоже, вы пытаетесь войти в нулевой файл. Какая строка 202 в BillingConsu.java? 28.05.2013
  • Как говорит @whoAmI. Кажется, это проблема конфигурации log4j, а не проблема, связанная с пулом потоков... 28.05.2013
  • @whoAmI Это resp = new StsSmsConnection().doRequest(sms); Но это тот же файл, который запускается ExecutorService!! и не исключение 28.05.2013
  • @fge Но в ExecutorService нет проблем с log4j .. программа работает .. 28.05.2013
  • В любом случае, вы должны добавить конфигурацию log4j в сообщение, возможно, это покажет проблему. 28.05.2013
  • @fge Добавлен файл конфигурации log4j 28.05.2013
  • Можете ли вы опубликовать код для LogFileWriter.append? 28.05.2013
  • @JohnVint Добавил этот код метода! Спасибо 28.05.2013

Ответы:


1

Как я и ожидал, вы терпите неудачу из-за локальности потока. Строка здесь почти наверняка возвращает null

MDC.get(ORIG_LOG_FILE_NAME)

Когда/где ты MDC.put? Проблема здесь в том, что MDC использует локальную карту потока. Поэтому, когда вы запускаете Callable, он попытается войти в отдельный поток. Этот поток не был зарегистрирован в MDC, и get вернет значение null.

Представьте, что ваше приложение похоже на

Main-Thread
  MDC.put -> sets thread-local-map(Main-Thread, ORIG_LOG_FILE_NAME)

Executor-Thread-1
Executor-Thread-2
Executor-Thread-N

Теперь, когда вы находитесь в Executor-Thread-1..N, это будет делать

Executor-Thread-N
    MDC.get(Executor-Thread-N, ORIG_LOG_FILE_NAME)

Он вернет ноль

Если вы работаете вне потоков службы Executor, он работает

Main-Thread
   MDC.get(Main-Thread, ORIG_LOG_FILE_NAME) // will be non-null

Итак, ваш следующий вопрос: «Почему не происходит сбой с ExecutorService?» Это, вероятно, или было бы и не может быть сообщено. Я заметил, что ваш порядок отправки в ExecutorService отличается от TPE. Возможно, вы захотите попробовать сопоставить их и посмотреть, получите ли вы тот же результат.

Изменить: может захотеть попробовать это как исправление

ThreadFactory threadFactory = new ThreadFactory() {
    public Thread newThread(final Runnable r) {
        return Executors.defaultThreadFactory().newThread(new Runnable(){
            public void run() {
                MDC.put(ORIG_LOG_FILE_NAME, fileName);
                r.run();
            }
        });
    }
};
28.05.2013
  • Это произошло, когда я закомментировал весь код вывода сообщения журнала!! 28.05.2013
  • Я добавил код для кода MDC.put, который находится в LogFileWriter. 28.05.2013
  • Посмотрите, сможете ли вы вызвать MDC.put(ORIG_LOG_FILE_NAME, fileName); из метода BillingConsu.call до doStsBilling. Вероятно, это не то исправление, которое вы хотите. Я опубликую, возможно, лучшее решение, если это сработает. 28.05.2013
  • Я удалил весь код, относящийся к log4j, из всех классов... и теперь он работает... Так что это доказывает... что-то связанное с log4j. Я попробую ваш путь и вернусь .. Я думаю, что вы нацелились на MDC.get и part part! 28.05.2013
  • @MadanMadan Обновлено чем-то, что вы можете попытаться использовать для решения этой проблемы, не помещая это в Callable. 28.05.2013
  • Спасибо друг! вы спасли мои дни!!! LogWriter был виновником здесь!! Миллиард раз спасибо..!!! 28.05.2013
  • давайте продолжим это обсуждение в чате 28.05.2013
  • Новые материалы

    Понимание СТРУКТУРЫ ДАННЫХ И АЛГОРИТМА.
    Что такое структуры данных и алгоритмы? Термин «структура данных» используется для описания того, как данные хранятся, а алгоритм используется для описания того, как данные сжимаются. И данные, и..

    Как интегрировать модель машинного обучения на ios с помощью CoreMl
    С выпуском новых функций, таких как CoreML, которые упростили преобразование модели машинного обучения в модель coreML. Доступная модель машинного обучения, которую можно преобразовать в модель..

    Создание успешной организации по науке о данных
    "Рабочие часы" Создание успешной организации по науке о данных Как создать эффективную группу по анализу данных! Введение Это обзорная статья о том, как создать эффективную группу по..

    Технологии и проблемы будущей работы
    Изучение преимуществ и недостатков технологий в образовании В быстро меняющемся мире технологии являются решающим фактором в формировании будущего работы. Многие отрасли уже были..

    Игорь Минар из Google приедет на #ReactiveConf2017
    Мы рады сообщить еще одну замечательную новость: один из самых востребованных спикеров приезжает в Братиславу на ReactiveConf 2017 ! Возможно, нет двух других кланов разработчиков с более..

    Я собираюсь научить вас Python шаг за шагом
    Привет, уважаемый энтузиаст Python! 👋 Готовы погрузиться в мир Python? Сегодня я приготовил для вас кое-что интересное, что сделает ваше путешествие более приятным, чем шарик мороженого в..

    Альтернатива шаблону исходящих сообщений для архитектуры микросервисов
    Познакомьтесь с двухэтапным сообщением В этой статье предлагается альтернативный шаблон для папки Исходящие : двухэтапное сообщение. Он основан не на очереди сообщений, а на..