【发布时间】:2011-09-27 20:46:41
【问题描述】:
我在 Solaris 10 上运行 Java 1.5。 我的程序是一个独立的java程序,使用java并发包和log4j-1.2.12.jar来记录某些信息。主要逻辑如下
ExecutorService executor = new AppThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(Integer.MAX_VALUE), new AppThreadFactory("BSRT", true), new ThreadPoolExecutor.CallerRunsPolicy());
CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(executor);
for (final Integer id : taskList) {
Callable<Integer> c = new Callable<Integer>() {
public Integer call() throws Exception {
int newId = DB operation(id);
return newId;
}
};
completionService.submit(c);
}
logger.debug("Start retrievie result");
for (Integer id : taskList) {
try {
Future<Integer> future = completionService.poll(1, TimeUnit.SECONDS);
Integer taskId=null;
if (future != null) {
logger.debug("future is obtained.");
taskId = future.get();
} else {
logger.error("wait too long and get nothing!");
break;
}
if (taskId != null) {
taskIdList.add(taskId);
}
} catch (ExecutionException ignore) {
// log the cause and ignore this aborted task,coninue with
// next available task.
logger.warn(ignore.getCause());
} catch (InterruptedException e) {
logger.warn("interrupted...");
// Re-assert the thread’s interrupted status
Thread.currentThread().interrupt();
}
}executor.shutdown();
在执行我的程序期间,有时(并非总是)我会收到此错误...
executor.shutdown();
调用super.run();返回后将无法中断AppThread
因为woker 已经从ThreadPoolExecutor 内部使用的worker 集中移除,所以executor 从那时起没有对AppThread 的引用。
顺便说一句:日志文件可访问且大小足够大。
log4j:ERROR Failed to flush writer,
java.io.InterruptedIOException
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:260)
at sun.nio.cs.StreamEncoder$CharsetSE.writeBytes(StreamEncoder.java:336)
at sun.nio.cs.StreamEncoder$CharsetSE.implFlushBuffer(StreamEncoder.java:404)
at sun.nio.cs.StreamEncoder$CharsetSE.implFlush(StreamEncoder.java:408)
at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:152)
at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:213)
at org.apache.log4j.helpers.QuietWriter.flush(QuietWriter.java:57)
at org.apache.log4j.WriterAppender.subAppend(WriterAppender.java:315)
at org.apache.log4j.DailyRollingFileAppender.subAppend(DailyRollingFileAppender.java:358)
at org.apache.log4j.WriterAppender.append(WriterAppender.java:159)
at org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:230)
at org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:65)
at org.apache.log4j.Category.callAppenders(Category.java:203)
at org.apache.log4j.Category.forcedLog(Category.java:388)
at org.apache.log4j.Category.debug(Category.java:257)
at AppThread.run( AppThread.java: 33)
33 是行:if (debug)
logger.info("Exiting " + getName());
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.log4j.Logger;
public class AppThread extends Thread {
public static final String DEFAULT_NAME = "MyAppThread";
private static volatile boolean debugLifecycle = false;
private static final AtomicInteger created = new AtomicInteger();
private static final AtomicInteger alive = new AtomicInteger();
private static final Logger logger = Logger.getLogger(AppThread.class);
private boolean dump = false;
public AppThread(Runnable r) {
this(r, DEFAULT_NAME);
}
public AppThread(Runnable runnable, String name) {
super(runnable, name + "-" + created.incrementAndGet());
logger.debug(name + "'s constructor running");
}
public void interrupt() {
if (!dump) {
super.interrupt();
}
if (dump) {
logger.debug("interrupt : " + getName() + " <<<");
Thread.dumpStack();
logger.debug("interrupt : " + getName() + " >>>");
}
}
public void run() {
boolean debug = debugLifecycle;
if (debug)
logger.info("Created " + getName());
try {
alive.incrementAndGet();
super.run();
logger.debug("running!");
} finally {
alive.decrementAndGet();
dump = true;
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
logger.debug(e);
}
if (debug)
logger.info("Exiting " + getName());
}
}
public static int getThreadsCreated() {
return created.get();
}
public static int getThreadsAlive() {
return alive.get();
}
public static boolean getDebug() {
return debugLifecycle;
}
public static void setDebug(boolean b) {
debugLifecycle = b;
}
}
另外一个问题是为了调试java.io.InterruptedIOException的原因,我加了
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
logger.debug(e);
}
在 AppThread 的 run 方法的 finally 子句中。当 InterruptedException 在 finally 子句中被捕获时,永远不会调用覆盖 interrupt() 方法。那么谁来中断 AppThread 呢? java.io.InterruptedIOException是同一个人吗?
【问题讨论】:
-
我修改了代码,只调用了 executor.shutdown();但问题依然存在。
-
是否有理由使用自定义线程工厂和自定义执行器?如果您只想知道谁调用了
Thread.interrupt(),请在该方法上放置一个断点。另外,您是否尝试使用股票执行器而不是特殊的线程工厂来排除AppThreadPoolExecutor/AppThread类中的错误? -
在windows环境下从未发生过。它只发生在运行 Solaris 10 的服务器上。更好的日志记录和统计信息是自定义线程工厂和执行程序的唯一原因。这些错误不会影响应用程序的正确性。试着理解它为什么会发生。
标签: java multithreading log4j java-io java.util.concurrent