多线程Java控制台应用程序在一台服务器上逐渐变慢

多线程Java控制台应用程序在一台服务器上逐渐变慢,java,multithreading,console,Java,Multithreading,Console,我有一个多线程Java应用程序,可以执行以下操作: 在主线程中递归迭代文件夹中的所有文件 为每个文件启动一个新线程(Runnableimpl) 线程检查文件是否已转换。(转换=复制+添加扩展名+生成元数据文件) 如果是,则跳过它并结束线程。如果不是,则转换文件,然后线程结束 我已经在许多机器和服务器上使用过这个应用程序,有不同的最大线程(4-8-10-25),除了我们最新的服务器,它一直运行得非常平稳和快速 服务器信息: 操作系统:Win2012 64位,HyperV虚拟机 Java:JDK

我有一个多线程Java应用程序,可以执行以下操作:

  • 在主线程中递归迭代文件夹中的所有文件
  • 为每个文件启动一个新线程(
    Runnable
    impl)
  • 线程检查文件是否已转换。(转换=复制+添加扩展名+生成元数据文件)
  • 如果是,则跳过它并结束线程。如果不是,则转换文件,然后线程结束
  • 我已经在许多机器和服务器上使用过这个应用程序,有不同的最大线程(4-8-10-25),除了我们最新的服务器,它一直运行得非常平稳和快速

    服务器信息:

    • 操作系统:Win2012 64位,HyperV虚拟机
    • Java:JDK 1.7.08064位
    在这个特定的服务器上,应用程序启动速度很快,几分钟后逐渐变慢。示例:处理文档(通过线程组合)通常平均需要15毫秒,现在转换文档甚至跳过文档需要30分钟后的一秒钟

    我使用任务管理器和JVisualVM来检查正在发生的事情,但我无法确定问题所在

    意见:

    • CPU在任何虚拟内核上都不接近100%
    • RAM只使用了50%
    • 磁盘I/O似乎也正常
    • McAfee没有扫描所有文档(我们已检查)
    • Java是用
      -Xms1024m-Xmx3072m
      启动的,只使用了500MB的初始内存
    • PermGen没问题
    • 从JVisualVM手动收集垃圾并不能提高速度
    • 立即重新启动应用程序会使它再次快速运行,但几分钟后它会再次减速
    • 我发现我的所有线程在JVisualVM中几乎总是处于“Park”状态。我不知道这是否正常
    • 我们尝试在Thread类内的finally块中添加
      LockSupport.unpark(Thread.currentThread())
      ,但没有任何效果
    代码片段:

    为每个文件启动线程:

    ThreadCountAwareThreadFactory threadFactory = ThreadCountAwareThreadFactory.getThreadFactory();
    executor = Executors.newFixedThreadPool(getMaxThreads(), threadFactory);
    
    //iterate files here and for each file do the following
    for(...) {
        ContentProvider contentProvider = springHelper.getBean(ContentProvider.class);          
        MetadataProvider metadataProvider = springHelper.getBean(MetadataProvider.class);
        ScopeSelector scopeSelector = springHelper.getBean(ScopeSelector.class);
    
        ThreadDataPackage dpkg = dataPackagesIterator.next();
        executor.execute(new TransformThread(dpkg, contentProvider, metadataProvider, scopeSelector, file, getOutputDir()));
    }
    
    //after all files have a thread launched
    try {
        executor.shutdown();
    
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        log.info(String.format("All threads (%s) completed...", threadFactory.getSpawnedThreadCount()));
    } catch(InterruptedException ie) {
        log.log(Level.SEVERE, "Error occurred when waiting for threads to complete...", ie);
    }
    
    TransformThread类(扩展
    BaseThread
    ,它只是一个抽象类,带有线程包的setter/getter):

    有人知道是什么导致了服务器的速度变慢吗

        public class TransformThread extends BaseThread {
    
        private File file; 
        private Logger log;
        private ContentProvider contentProvider;
        private MetadataProvider metadataProvider;
        private ScopeSelector scopeSelector;
        private String outputDir;
        private String identifier;
    
        public TransformThread(ThreadDataPackage dataPackage, ContentProvider contentProvider, 
            MetadataProvider metadataProvider, ScopeSelector scopeSelector, File file, String outputDir) {
            super(dataPackage);
            this.contentProvider = contentProvider;
            this.metadataProvider = metadataProvider;
            this.file = file;
            this.log = dataPackage.getLog();
            this.outputDir = outputDir;
            this.scopeSelector = scopeSelector;
            this.identifier = "TransformThread" + hashCode();
        }
    
        @Override
        public void run() {
                try {
                logInfo(">>>> Processing file " + file.getAbsolutePath(), null);
    
                //check if already processed
                if(isAlreadyProcessed(file)) {
                    logInfo(">>>> File was already processed, skipping...", null);
                    return;
                }
    
                contentProvider.setFilePath(file.getAbsolutePath());
    
                //process metadata
                logInfo(">>>> Processing metadata", null);
    
                //do some metadata processing and copy the file to the output directory, change extension, etc...
    
            } catch(Exception e) {
                logSevere("Error occurred during transform", e);
            Transform.addFailedFile(String.format("%s (%s)", file.getAbsolutePath(), e.getMessage()));
            } finally {
                LockSupport.unpark(Thread.currentThread());
            }
        }
    
        private void logInfo(String msg, Throwable error) {
            doLog(Level.INFO, msg, this.identifier, error);
        }
    
        private void logSevere(String msg, Throwable error) {
            doLog(Level.SEVERE, msg, this.identifier, error);
        }
    
        private void doLog(Level lvl, String msg, String identifier, Throwable error) {
            log.log(lvl, identifier + " - " + msg, error);
        }
    
        private boolean isAlreadyProcessed(File file) {
            return new File(file.getAbsolutePath() + Constants.PROCESSED_MARKER).exists();
        }
    
        protected void markProcessed(File file) 
                throws IOException {
            File processedMarker = new File(file.getAbsolutePath() + Constants.PROCESSED_MARKER);
            processedMarker.createNewFile();
        }
    
    }