jjzjj

Java ExecutorService 和 ThreadPoolExecutor

coder 2024-03-29 原文

我遇到了一个奇怪的问题。我正在尝试使用生产者/消费者模型,如果我在这里做错了什么,请提出建议。 当我使用固定线程 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);
 }

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

最佳答案

如我所料,您因为线程局部性而失败。这里的行几乎肯定返回 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 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();
            }
        });
    }
};

关于Java ExecutorService 和 ThreadPoolExecutor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16790064/

有关Java ExecutorService 和 ThreadPoolExecutor的更多相关文章

  1. java - 重写 ThreadPoolExecutor afterExecute 方法 - 有什么缺点吗? - 2

    钩子(Hook)方法的优点:beforeExecute(Thread,Runnable)和afterExecute(Runnable,Throwable)beforeExecute(Thread,Runnable)andafterExecute(Runnable,Throwable)methodsthatarecalledbeforeandafterexecutionofeachtask.Thesecanbeusedtomanipulatetheexecutionenvironment;forexample,reinitializingThreadLocals,gatheringsta

  2. java - 更改 ThreadPoolExecutor 的队列大小 - 2

    我需要能够更改ThreadPoolExecutor任务队列的大小.当然,BlockingQueue不支持改变大小,ThreadPoolExecutor也不支持改变队列。所以,我想出的方法是使用ThreadPoolExecutor.shutdownNow(),这会返回一个尚未执行的Runnable列表。然后我可以创建一个具有所需队列大小的新执行程序并重新提交所有任务。问题在于调用shutdownNow()时正在进行的任务。据我从javadoc中得知,执行程序将在当前执行任务的所有线程上调用Thread.interrupt()。我不希望我的任务被杀死。这个问题可能是询问如何编写我的任务以使

  3. java - 如何在 Java 中使用 ThreadPoolExecutor 处理 RejectedExecutionException - 2

    在Java中使用ThreadPoolExecutor时,处理RejectedExecutionException的最佳方法是什么?我想确保提交的任务不应该被忽视并且应该被执行。截至目前,完成任务没有硬性实时要求。我认为可以做的一件事是在一个循环中等待,直到我知道可运行队列中有空间,然后继续并将其添加到队列中。如果人们可以分享他们的经验,我们会很高兴。添加我想到的可能的解决方案:while(executor.getQueue().remainingCapacity 最佳答案 我会改变你队列的行为。例如publicclassMyBloc

  4. Java ThreadPoolExecutor 策略, 'Direct Handoff' 带队列? - 2

    我希望有一个ThreadPoolExecutor,我可以在其中设置一个corePoolSize和一个maximumPoolSize,然后队列将切换任务立即进入线程池,从而创建新线程,直到达到maximumPoolSize,然后开始添加到队列中。有这样的事吗?如果没有,它没有这样的策略有什么充分的理由吗?我本质上想要的是提交任务执行,当它达到一个点,它基本上会因为有太多线程(通过设置maximumPoolSize)而获得“最差”性能时,它将停止添加新线程并且使用该线程池并开始排队,然后如果队列已满则拒绝。当负载回落时,它可以开始将未使用的线程拆除回corePoolSize。在我的申请中,

  5. java - 由 PriorityBlockingQueue 支持的 ThreadPoolExecutor 似乎不起作用 - 2

    我有大量图片要从服务器获取,我想获取一些优先级高于其他图片的图片,所以我实现了自己的ThreadPoolExecutor返回一个FutureTask实现了Comparable但它似乎不起作用。这些任务或多或少按照我将它们添加到队列的顺序进行处理。我已经调试了ThreadPoolExecutor的BlockingQueue并发现当我添加具有更高优先级的Runnable时,它并没有转移所有排在队列的顶部。这是代码publicclassPriorityThreadPoolExecutorextendsThreadPoolExecutor{publicPriorityThreadPoolExe

  6. Java ExecutorService 和 ThreadPoolExecutor - 2

    我遇到了一个奇怪的问题。我正在尝试使用生产者/消费者模型,如果我在这里做错了什么,请提出建议。当我使用固定线程4的ExecutorService时,我从来没有得到任何异常并且程序运行但是当我使用ThreadPoolExecutor时,它给了我异常。无法找出错误是什么!请指教!ExecutorService代码:ArrayBlockingQueuelist=newArrayBlockingQueue(2);ThreadFactorythreadFactory=Executors.defaultThreadFactory();ExecutorServicethreadPool=Execut

  7. java - 如何为 Async Spring 使用多个 threadPoolExecutor - 2

    我在两个类上使用Spring@Async。两者最终都实现了一个接口(interface)。我正在创建两个单独的ThreadPoolTask​​Executor,因此每个类都有自己的ThreadPool来处理。然而,由于我认为代理和Spring如何实现异步类,我必须将@Async注释放在基本接口(interface)上。因此,这两个类最终使用相同的ThreadPoolTask​​Executor。是否可以告诉Spring对于这个Bean(在本例中我将实现该接口(interface)的类称为服务),使用这个ThreadPoolTask​​Executor。 最佳

  8. java - ThreadPoolExecutor#getActiveCount() 到底有多 'approximate'? - 2

    ThreadPoolExecutor#getActiveCount()的javadocs假设该方法“返回正在执行任务的线程的大致数量。”是什么让这个数字是近似值而不是精确值?它会多报还是少报Activity线程?方法如下:/***Returnstheapproximatenumberofthreadsthatareactively*executingtasks.**@returnthenumberofthreads*/publicintgetActiveCount(){finalReentrantLockmainLock=this.mainLock;mainLock.lock();tr

  9. java - 如何删除 ThreadPoolExecutor 中的旧排队任务并插入新任务? - 2

    我使用ThreadPoolExecutor从互联网加载大量图像。当找到新图像时,我需要先渲染它,在这种情况下我想放弃仍在ThreadPoolExecutor中排队的旧任务并添加这些新项目进行下载。我发现ThreadPoolExecutor中没有“clearqueue”方法,“purge”方法听起来不太好。我该怎么办?我只是想调用这个执行器的“关闭”并重新创建一个新的执行器来执行此操作,不确定是否合适。 最佳答案 你试过吗?ThreadPoolExecutorpool=.....;pool.remove(task);task是您要删除

  10. java - ThreadPoolExecutor 和队列 - 2

    我认为使用ThreadPoolExecutor我们可以在构造函数中传递的BlockingQueue中或使用execute方法提交要执行的Runnable。另外我的理解是,如果任务可用,它将被执行。我不明白的是:publicclassMyThreadPoolExecutor{privatestaticThreadPoolExecutorexecutor;publicMyThreadPoolExecutor(intmin,intmax,intidleTime,BlockingQueuequeue){executor=newThreadPoolExecutor(min,max,10,Time

随机推荐