スレッドプール内のスレッドがすべて実行されたかどうかを判断


転載:http://www.cnblogs.com/stonefeng/p/5967451.html
1、マルチスレッドを使用する場合java.util.concurrent.Executorsのスレッドプールを使用する場合があります.複数のスレッドが非同期で実行される場合、スレッドプール内のすべてのサブスレッドが実行されたかどうかを判断するのはよくありませんが、この判断は役に立つ場合があります.例えば、1つのファイルに非同期でコンテンツを書き込む方法があります.すべてのサブスレッドが書き込まれた後、ファイルの末尾に「-END-」と書くか、ファイルストリームを閉じるかなど、スレッドプール内のすべてのサブスレッドが実行されたかどうかを示すフラグビットが必要です.この方法で判断します.
public class MySemaphore {

    public static void main(String[] args) throws IOException, InterruptedException {
        final File stream = new File("c:\\temp\\stonefeng\\stream.txt");
        final OutputStream os = new FileOutputStream(stream);
        final OutputStreamWriter writer = new OutputStreamWriter(os);
        final Semaphore semaphore = new Semaphore(10);
        ExecutorService exec = Executors.newCachedThreadPool();

        final long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            final int num = i;
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        writer.write(String.valueOf(num)+"
"
); semaphore.release(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }; exec.submit(task); } exec.shutdown(); while(true){ if(exec.isTerminated()){ writer.write("---END---
"
); writer.close(); System.out.println(" !"); break; } Thread.sleep(1000); } final long end = System.currentTimeMillis(); System.out.println((end-start)/1000); } }

ExecutorServices.shutdownメソッドが呼び出されると、スレッドプールは新しいタスクを受信しませんが、スレッドプールに追加されたタスクが処理済みになるまでスレッドプールはすぐに終了しません.shutdownメソッドを呼び出すと、デッドサイクルでisTerminatedメソッドでスレッドプール内のすべてのスレッドが実行済みかどうかを判断できます.サブスレッドが終了したら、ストリームを閉じるなどの後続操作ができます.
2、スレッドプール内のスレッドがすべて実行されたかどうかを判断するもう一つの解決策は、1つまたは複数のスレッドが1つのイベントのセットを待つことができるようにするロック(CountDownLatch)を使用して実現される.ロック状態は、待機するイベントの数を示す正数に初期化されたカウンタを含む.countDownメソッド減算カウンタは、イベントが発生したことを示し、awaitメソッド待機カウンタがゼロに達したことを示します.つまり、待機する必要があることを示します.ロックを使用して、プログラムを設計して目的を達成することができます.
public class CountDownLatchApproach {
    public static void main(String[] args) throws IOException, InterruptedException {
        final int nThreads = 10;
        final CountDownLatch endGate = new CountDownLatch(nThreads);
        final File stream = new File("c:\\temp\\stonefeng\\stream.txt");
        final OutputStream os = new FileOutputStream(stream);
        final OutputStreamWriter writer = new OutputStreamWriter(os);
        ExecutorService exec = Executors.newCachedThreadPool();
        for (int i = 0; i < nThreads; i++) {
            final int num = i;
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    try {
                        writer.write(String.valueOf(num)+"
"
); } catch (IOException e) { e.printStackTrace(); } finally { endGate.countDown(); } } }; exec.submit(task); } endGate.await(); writer.write("---END---
"
); writer.close(); } }

短所:性能が悪い
3、第3の方案、その実行性能も悪くない.
public class MySemaphore {

    public static void main(String[] args) throws IOException, InterruptedException {
        final File stream = new File("c:\\temp\\stonefeng\\stream.txt");
        final OutputStream os = new FileOutputStream(stream);
        final OutputStreamWriter writer = new OutputStreamWriter(os);
        final Semaphore semaphore = new Semaphore(10);
        ExecutorService exec = Executors.newCachedThreadPool();

        final long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            final int num = i;
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        writer.write(String.valueOf(num)+"
"
); semaphore.release(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }; exec.submit(task); } exec.shutdown(); exec.awaitTermination(1, TimeUnit.HOURS); writer.write("---END---
"
); writer.close(); System.out.println(" "); final long end = System.currentTimeMillis(); System.out.println((end-start)/1000); } }