2013-05-28 173 views
5

我遇到了一個奇怪的問題。我試圖使用生產者/消費者模型,請建議如果我在這裏做錯了什麼。 當我使用固定線程爲4的ExecutorService時,我從來沒有得到任何異常和程序運行,但是當我使用ThreadPoolExecutor時,它給了我例外。找不到錯誤!請指教! ExecutorService中的Java ExecutorService和ThreadPoolExecutor

代碼:

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(); 
} 
+2

貌似你試圖登錄到空文件。 BillingConsu.java中202是什麼? – BobTheBuilder

+0

就像@whoAmI說的。這似乎是一個log4j配置問題,而不是線程池相關的問題... – fge

+0

@whoAmI它是resp =新的StsSmsConnection()。doRequest(sms);但它是由ExecutorService運行的相同文件!並沒有例外 –

回答

8

正如我所料,你是因爲線程本地的失敗。這裏的線路幾乎肯定返回null

MDC.get(ORIG_LOG_FILE_NAME) 

時/你在哪裏MDC.put?這裏的問題是MDC使用線程局部映射。所以當你運行Callable時,它會嘗試登錄一個單獨的線程。該線程尚未使用MDC註冊,並且get將返回空值。

想象一下你的應用程序看起來類似於

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

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

現在,當你在執行程序線程1..1它會做

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

它將返回null

如果您在Executor Service線程外運行

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(); 
      } 
     }); 
    } 
}; 
+0

當我註釋掉所有Log消息輸出代碼時,發生了這種情況! –

+0

我已經添加了LogFileWriter中的MDC.put代碼的代碼 –

+0

看看您是否可以在'doStsBilling'之前的'BillingConsu.call'方法中調用'MDC.put(ORIG_LOG_FILE_NAME,fileName);'。可能不是你想要的修復。如果可行的話,我會發佈一個更好的解決方案。 –

相關問題