Author: bpoussin Date: 2010-04-27 18:54:55 +0200 (Tue, 27 Apr 2010) New Revision: 1755 Log: simplify multi-threading, run-its test work, but more test must be done Modified: trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParserMojo.java trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/ParserThread.java Modified: trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParserMojo.java =================================================================== --- trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParserMojo.java 2010-04-21 17:28:12 UTC (rev 1754) +++ trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/AbstractI18nParserMojo.java 2010-04-27 16:54:55 UTC (rev 1755) @@ -201,6 +201,7 @@ } } + // thread is started when we add the first file thread = new ParserThread(this); } @@ -241,8 +242,6 @@ oldLanguage.load(oldLanguageFile); - thread.start(); - // Parsing if (treateDefaultEntry) { addDefaultEntry(); @@ -281,6 +280,8 @@ getLog().debug("ask to terminate " + thread); } + // all files are send to thread, we ask termination of thread. + // this termination treat all sending file before really stop thread.terminatesAndWaits(); List<File> treadedFiles = thread.getTreatedFiles(); Modified: trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/ParserThread.java =================================================================== --- trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/ParserThread.java 2010-04-21 17:28:12 UTC (rev 1754) +++ trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/ParserThread.java 2010-04-27 16:54:55 UTC (rev 1755) @@ -33,7 +33,13 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.*; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; /** * A thread to launch parser on files. @@ -61,18 +67,9 @@ /** number of files registred to consume */ protected int nbFiles; - /** - * object used to lock method {@link #terminatesAndWaits()} until the thread - * is not fully terminated. - */ - private final Object lock = new Object(); + /** permit to stop thread and executor */ + boolean quitAsked = false; - /** - * object used to lock in {@link #run()} until all tasks are consumed after - * the shutdown of the executor - */ - private final Object lock2 = new Object(); - public ParserThread(I18nParserConfiguration configuration) { super(ParserThread.class.getSimpleName()); this.configuration = configuration; @@ -129,6 +126,10 @@ getLog().info("[" + nbFiles + "] " + f); } tasks.offer(new ParserTask(parser, f)); + if (!isAlive()) { + // we are sure that we have 1 file to treat, we start the thread + start(); + } } } @@ -141,53 +142,10 @@ * <b>Note:</b> The method does not return until all files are not * consumed. */ - public synchronized void terminatesAndWaits() { - - if (isVerbose()) { - getLog().info("add terminate runner"); - } - tasks.offer(new ParserTask(null, null)); - - // we waits a little time to make sure, the thread receive the - // sentinel, we can not use a lock here - try { - Thread.sleep(100); - } catch (InterruptedException e) { - if (getLog().isErrorEnabled()) { - getLog().error(e); - } - } - - if (getNbFilesToTreate() > 0) { - - // there is still something to treate, - // MUST block until the thread is fully terminated - - if (isVerbose()) { - getLog().info("block until ends..."); - } - - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - if (getLog().isErrorEnabled()) { - getLog().error(e); - } - } - } - } - - if (getNbFilesToTreate() > 0) { - // this case should never happens : once we are here, all files - // MUST have been consumed - throw new IllegalStateException( - "should have " + nbFiles + " files treated, but found " + - treatedFiles.size()); - } - if (getLog().isDebugEnabled()) { - getLog().debug("thread is terminated."); - } + public void terminatesAndWaits() throws InterruptedException { + quitAsked = true; + // wait thread termination + this.join(); } @Override @@ -196,32 +154,27 @@ // create pool executor ExecutorService executor = createExecutor(); - boolean canQuit = false; + // only quit loop if no more task in queue and quitAsked is true + while (!(quitAsked && tasks.size() == 0)) { - while (!canQuit) { - // waiting for a new file to treate ParserTask runner; try { - runner = tasks.take(); + // ask task on queue, wait 500ms until there is 1 file + // don't use take(), because we must check when user switch + // quitAsked flag with terminatesAndWaits() + runner = tasks.poll(500, TimeUnit.MILLISECONDS); + if (runner == null) { + // no file in queue, go to check quitAsked flag + continue; + } } catch (InterruptedException e) { if (getLog().isErrorEnabled()) { getLog().error(e); } - canQuit = true; - continue; + break; } - if (runner.getFile() == null) { - // ask to quit the tread - if (getLog().isDebugEnabled()) { - getLog().debug("Termination is asked..., will terminate to " + - "resting consume files"); - } - canQuit = true; - continue; - } - if (getLog().isDebugEnabled()) { getLog().debug("consume " + runner); } @@ -232,70 +185,38 @@ } } + // something append to ask the termination of thread, we stop executor // ask executor to terminate executor.shutdown(); - if (nbFiles == 0) { - // no file consumed - if (isVerbose()) { + if (isVerbose()) { + if (nbFiles == 0) { + // no file consumed getLog().info("No file consumed."); - } - } else { - if (isVerbose()) { + } else { getLog().info("Will waits until all files (" + nbFiles + - ") are consumed (still " + getNbFilesToTreate() + - " file(s) to consume)"); + ") are consumed (still " + getNbFilesToTreate() + + " file(s) to consume)"); } } - // waits end of executor - canQuit = false; + try { + // wait until all submited jobs are terminated + // i don't want timeout, i think 2 days is good :) + executor.awaitTermination(2, TimeUnit.DAYS); + } catch (InterruptedException e) { + getLog().error(e); + } - while (!canQuit) { - - int nbFilesToTreate = getNbFilesToTreate(); - - // can quit if and only if executore is terminated are there is no - // more files to consume - // Note : normally, the second test is not necessary... - canQuit = executor.isTerminated() || nbFilesToTreate == 0; - - if (canQuit) { - continue; - } - - if (getLog().isDebugEnabled()) { - getLog().debug("Waiting end... (still " + nbFilesToTreate + - " file(s) to consume)"); - } - - // waits a task to be done - synchronized (lock2) { - try { - lock2.wait(); - } catch (InterruptedException e) { - getLog().error(e); - break; - } - } - - if (getLog().isDebugEnabled()) { - getLog().debug("A task was consumed, still " + getNbFilesToTreate() + - " file(s) to treate."); - } + if (getLog().isDebugEnabled()) { + getLog().debug("A task was consumed, still " + getNbFilesToTreate() + + " file(s) to treate."); } if (isVerbose()) { getLog().info("Executor is terminated, will release thread lock."); } - - // service was shutdown and terminated, release thread main lock. - - synchronized (lock) { - lock.notifyAll(); - } - } /** clean internal state after usage of the thread. */ @@ -336,18 +257,9 @@ @Override protected void afterExecute(Runnable r, Throwable t) { - try { - super.afterExecute(r, t); - ParserTask i18n = (ParserTask) r; - i18n.registerResult(treatedFiles, touchedFiles, getResult()); - } finally { - - // task is done, notify thread - - synchronized (lock2) { - lock2.notifyAll(); - } - } + super.afterExecute(r, t); + ParserTask i18n = (ParserTask) r; + i18n.registerResult(treatedFiles, touchedFiles, getResult()); } }; return executor;