Java线程恼人的行为

时间:2017-11-24 06:26:07

标签: java multithreading synchronization

我有以下方法,由大约100多个线程运行。

<Method Signature>
{
   System.out.println("Starting Thread with ID :- " + iThreadID);

   <Some piece of code which takes more than 10 seconds to complete>

   System.out.println("Finished Thread with ID :- " + iThreadID);
}

当线程执行时,我得到以下输出。

Starting Thread with ID :- 1
Starting Thread with ID :- 6
Starting Thread with ID :- 14
Starting Thread with ID :- 9
Starting Thread with ID :- 69
Starting Thread with ID :- 21
Starting Thread with ID :- 87
Starting Thread with ID :- 13
Starting Thread with ID :- 10
Starting Thread with ID :- 45
**Finished Thread with ID :- 1**
Starting Thread with ID :- 30
Starting Thread with ID :- 25
Starting Thread with ID :- 32
**Finished Thread with ID :- 87**
...

并非所有100个线程都一起启动。某些线程在创建其他线程之前完成其方法执行。

为什么会这样?有什么办法可以确保所有线程都是在执行代码之前创建的吗?

1 个答案:

答案 0 :(得分:7)

来自comment

  

我想要的是所有线程必须先执行一组代码才能在其中任何一个代码执行该代码之后执行代码。

使用CountDownLatch。 javadoc准确描述了您的需求:

  

允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。

如果您想多次这样做,请使用CyclicBarrier

  

一种同步辅助工具,允许一组线程全部等待彼此到达公共障碍点。 CyclicBarriers在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。屏障称为循环,因为它可以在等待线程释放后重新使用。

以下代码显示了两者。

测试助手方法

private static void test(int count, Supplier<Thread> threadProducer) {
    Thread[] threads = new Thread[count];
    for (int i = 0; i < count; i++) {
        threads[i] = threadProducer.get();
        threads[i].start();
    }
    System.out.println("Ready");
    for (int i = 0; i < count; i++)
        try {
            threads[i].join();
        } catch (InterruptedException e) {
            System.out.println(threads[i].getName() + ": " + e);
        }
    System.out.println("All Done");
}

<强> CountDownLatch

class LatchThread extends Thread {
    private final CountDownLatch countDownLatch;
    public LatchThread(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }
    @Override
    public void run() {
        try {
            System.out.println(getName() + ": Started");
            this.countDownLatch.countDown();
            this.countDownLatch.await();
            System.out.println(getName() + ": Done");
        } catch (InterruptedException e) {
            System.out.println(getName() + ": " + e);
        }
    }
}

输出显示线程等到所有线程都已启动,即直到所有线程都调用countDown()

CountDownLatch countDownLatch = new CountDownLatch(10);
test(10, () -> new LatchThread(countDownLatch));
Thread-0: Started
Thread-4: Started
Thread-5: Started
Thread-3: Started
Thread-2: Started
Thread-1: Started
Thread-8: Started
Thread-9: Started
Thread-6: Started
Thread-7: Started
Ready
Thread-7: Done
Thread-4: Done
Thread-2: Done
Thread-0: Done
Thread-6: Done
Thread-8: Done
Thread-1: Done
Thread-9: Done
Thread-3: Done
Thread-5: Done
All Done

<强> CyclicBarrier

class BarrierThread extends Thread {
    private final CyclicBarrier cyclicBarrier;
    public BarrierThread(CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;
    }
    @Override
    public void run() {
        try {
            System.out.println(getName() + ": Started");
            if (this.cyclicBarrier != null) this.cyclicBarrier.await();
            System.out.println(getName() + ": Phase 1");
            if (this.cyclicBarrier != null) this.cyclicBarrier.await();
            System.out.println(getName() + ": Phase 2");
            if (this.cyclicBarrier != null) this.cyclicBarrier.await();
            System.out.println(getName() + ": Done");
        } catch (InterruptedException | BrokenBarrierException e) {
            System.out.println(getName() + ": " + e);
        }
    }
}

输出显示线程在进入下一阶段之前相互等待。

CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
test(10, () -> new BarrierThread(cyclicBarrier));
Thread-0: Started
Thread-5: Started
Thread-4: Started
Thread-2: Started
Thread-6: Started
Thread-1: Started
Thread-3: Started
Thread-7: Started
Thread-9: Started
Thread-8: Started
Ready
Thread-8: Phase 1
Thread-5: Phase 1
Thread-4: Phase 1
Thread-6: Phase 1
Thread-0: Phase 1
Thread-9: Phase 1
Thread-7: Phase 1
Thread-3: Phase 1
Thread-1: Phase 1
Thread-2: Phase 1
Thread-2: Phase 2
Thread-8: Phase 2
Thread-6: Phase 2
Thread-7: Phase 2
Thread-1: Phase 2
Thread-4: Phase 2
Thread-5: Phase 2
Thread-3: Phase 2
Thread-9: Phase 2
Thread-0: Phase 2
Thread-0: Done
Thread-8: Done
Thread-4: Done
Thread-2: Done
Thread-9: Done
Thread-3: Done
Thread-5: Done
Thread-1: Done
Thread-6: Done
Thread-7: Done
All Done

相比之下,没有障碍,输出显示线程不会相互等待。

test(10, () -> new BarrierThread(null));
Thread-0: Started
Ready
Thread-4: Started
Thread-4: Phase 1
Thread-4: Phase 2
Thread-4: Done
Thread-1: Started
Thread-1: Phase 1
Thread-1: Phase 2
Thread-1: Done
Thread-5: Started
Thread-5: Phase 1
Thread-5: Phase 2
Thread-5: Done
Thread-2: Started
Thread-2: Phase 1
Thread-2: Phase 2
Thread-2: Done
Thread-3: Started
Thread-6: Started
Thread-6: Phase 1
Thread-7: Started
Thread-9: Started
Thread-9: Phase 1
Thread-8: Started
Thread-8: Phase 1
Thread-8: Phase 2
Thread-8: Done
Thread-0: Phase 1
Thread-0: Phase 2
Thread-0: Done
Thread-9: Phase 2
Thread-9: Done
Thread-7: Phase 1
Thread-7: Phase 2
Thread-7: Done
Thread-6: Phase 2
Thread-3: Phase 1
Thread-3: Phase 2
Thread-3: Done
Thread-6: Done
All Done