java多线程-主线程等待多个子线程处理结果,子线程结果不完整

public class ThreadTest {

public static void main(String[] args) {
    System.out.println("main begin");
    CountDownLatch cunt = new CountDownLatch(5);
    List<String> out = new ArrayList<>();
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    for (int i=0;i<5;i++){
        executorService.execute(new TaskTest(i+"",cunt,out));
    }
    try {
        cunt.await();
    }catch (Exception e){

    }
    executorService.shutdown();
    System.out.println(out);
    System.out.println("main out");
}

}
@Data
@NoArgsConstructor
@AllArgsConstructor
class TaskTest implements Runnable{

private String name;
private CountDownLatch countDownLatch;
private List<String> result;

@Override
public void run() {
    countDownLatch.countDown();
    result.add(Thread.currentThread().getName()+":"+name);
    System.out.println("thread:"+name);
}

}
主线程中打印的out理论上应该是:[11, 11, 11, 11, 11],但是会出现[null, 11, 11, 11, 11]或者[null, null, 11, 11, 11],是什么原因?

不用线程池的话,主线程中可以通过监测子线程的状态来判断。

public static void main(String[] args) {
    System.out.println("main start");
    ThreadGroup tg = new ThreadGroup("Parent ThreadGroup");
    for (int j = 0; j < 10; j++) {
        new Thread(tg, "t" + j) {
            public void run() {
                System.out.println("Thread: " + getName() + " running");
                int small = 0;
                int large = 10;
                try {
                    Thread.sleep(1000 * (int) (Math.random() * (large - small + 1) + small));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
    while (tg.activeCount() > 0) {
        try {
            System.out.println("Waiting for " + tg.activeCount() + " CThreads to Complete");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println("main end");
}

public void run() {
countDownLatch.countDown();
result.add(Thread.currentThread().getName()+":"+name);
System.out.println("thread:"+name);
}

countDown()方法放在最后调用

改成下面这样,执行完逻辑之后才放开,确保业务逻辑先执行

@Override
public void run() {
 result.add(Thread.currentThread().getName()+":"+name);
    System.out.println("thread:"+name);
    countDownLatch.countDown();
}

但是你这里还是有个问题,你的out数组不是线程安全的,我简单改了一下,

public static void main(String[] args) {
        System.out.println("main begin");
        CountDownLatch cunt = new CountDownLatch(5);
        ArrayBlockingQueue<String> queue=new ArrayBlockingQueue<>(5);
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i=0;i<5;i++){
            int finalI = i;
            executorService.execute(()->{
               
                try {
                    queue.put(Thread.currentThread().getName()+":"+ finalI);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread:"+ finalI);
                cunt.countDown();
            });
        }
        try {
            cunt.await();
        }catch (Exception e){
            e.printStackTrace();
        }
        executorService.shutdown();
        while (queue.size()!=0){
            System.out.println(queue.poll());
        }
        System.out.println("main out");
    }