Java ExecutorService和ThreadPoolExecutor

Mad*_*dan 6 java multithreading executorservice

我遇到了一个奇怪的问题.我正在尝试使用制作人/消费者模型,请在此处建议我是否做错了.当我使用固定线程为4的ExecutorService时,我从未得到任何异常并且程序运行但是当我使用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);
 }
Run Code Online (Sandbox Code Playgroud)

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);
           }
Run Code Online (Sandbox Code Playgroud)

运行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) 
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

MDC将代码放在LogFileWriter中

@Override
public void activateOptions() {
MDC.put(ORIG_LOG_FILE_NAME, fileName);
super.activateOptions();
 }
Run Code Online (Sandbox Code Playgroud)

Joh*_*int 8

正如我所料,你因为线程局部性而失败.这里的线几乎肯定会返回null

MDC.get(ORIG_LOG_FILE_NAME)
Run Code Online (Sandbox Code Playgroud)

你何时/何地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
Run Code Online (Sandbox Code Playgroud)

现在当你在Executor-Thread-1..N时,它会做

Executor-Thread-N
    MDC.get(Executor-Thread-N, ORIG_LOG_FILE_NAME)
Run Code Online (Sandbox Code Playgroud)

它将返回null

如果您在Executor Service线程之外运行,它就可以运行

Main-Thread
   MDC.get(Main-Thread, ORIG_LOG_FILE_NAME) // will be non-null
Run Code Online (Sandbox Code Playgroud)

所以你的下一个问题是,"为什么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();
            }
        });
    }
};
Run Code Online (Sandbox Code Playgroud)