多线程Java控制台应用程序在一台服务器上逐渐变慢
我有一个多线程Java应用程序,可以执行以下操作:多线程Java控制台应用程序在一台服务器上逐渐变慢,java,multithreading,console,Java,Multithreading,Console,我有一个多线程Java应用程序,可以执行以下操作: 在主线程中递归迭代文件夹中的所有文件 为每个文件启动一个新线程(Runnableimpl) 线程检查文件是否已转换。(转换=复制+添加扩展名+生成元数据文件) 如果是,则跳过它并结束线程。如果不是,则转换文件,然后线程结束 我已经在许多机器和服务器上使用过这个应用程序,有不同的最大线程(4-8-10-25),除了我们最新的服务器,它一直运行得非常平稳和快速 服务器信息: 操作系统:Win2012 64位,HyperV虚拟机 Java:JDK
Runnable
impl)
- 操作系统:Win2012 64位,HyperV虚拟机
- Java:JDK 1.7.08064位
- CPU在任何虚拟内核上都不接近100%
- RAM只使用了50%
- 磁盘I/O似乎也正常
- McAfee没有扫描所有文档(我们已检查)
- Java是用
启动的,只使用了500MB的初始内存-Xms1024m-Xmx3072m
- 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();
}
}