多线程并发 之 判断线程任务是否全部结束

1、前言

我们多线程处理任务的时候,有时候需要多线程都执行完成的情况下才能执行其他的任务。这种情况下我们就需要判断多线程什么时候执行完。有以下几种方法,大家可以根据情况自行选择

2、实现方案

2.1、方案:isTerminated

使用isTerminated来判断所有任务都已完成,会返回true。但是前提是启用shutdown顺序关闭。

package com.wzl.xman.servicea.service.impl;

import com.wzl.xman.servicea.service.ThreadBizService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
public class ThreadBizServiceImpl implements ThreadBizService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void threadBizMethod01(String groupName) throws Exception {
        logger.info(groupName + "==threadBizMethod Start==");
        ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 2000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(500));
        for (int i = 1; i <= 10; i++) {
            MyThreadRunnable01 runnable = new MyThreadRunnable01(groupName, i * 1000);
            executor.execute(runnable);
        }
        executor.shutdown();
        while (true) {
            if (executor.isTerminated()) {
                System.out.println("所有的子线程都结束了!");
                break;
            }
            Thread.sleep(1000);//休眠1秒钟
        }
        logger.info(groupName + "==threadBizMethod End==");
    } 

}

/**
 * 线程处理类
 */
class MyThreadRunnable01 implements Runnable {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private long millis;
    private String groupName;

    public MyThreadRunnable01(String groupName, long millis) {
        this.groupName = groupName;
        this.millis = millis;
    }

    @Override
    public void run() {
        try {
            logger.info(groupName + "开始处理业务!" + millis);
            Thread.sleep(millis);
            logger.info(groupName + "处理业务结束!" + millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

使用isTerminated来判断所有任务是否都已完成,需要先执行线程池的shutdown方法,对于线程池是共享的情况不是很友好!!!

2.2、方案:CountDownLatch

CountDownLatch是一个同步辅助类,用来判断多线程是否执行完成。
它的原理是先声明一个运行N个线程任务,每完成一个线程任务,计数器就减1。当计数器等于0,说明所有的多线程都运行完成了。

package com.wzl.xman.servicea.service.impl;

import com.wzl.xman.servicea.service.ThreadBizService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
public class ThreadBizServiceImpl implements ThreadBizService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private final static ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 2000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(500));

    @Override
    public void threadBizMethod02(String groupName) {
        logger.info(groupName + "==threadBizMethod Start==");
        CountDownLatch countDownLatch = new CountDownLatch(10);//确定会启动10个线程任务
        for (int i = 1; i <= 10; i++) {
            MyThreadRunnable runnable = new MyThreadRunnable(countDownLatch, groupName, i * 1000);
            executor.execute(runnable);
        }
        try {
            countDownLatch.await();//多线程运行结束前自旋等待
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info(groupName + "==threadBizMethod End==");

    }
}

/**
 * 线程处理类
 */
class MyThreadRunnable implements Runnable {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private long millis;
    private String groupName;
    private CountDownLatch countDownLatch;

    public MyThreadRunnable(CountDownLatch countDownLatch, String groupName, long millis) {
        this.countDownLatch = countDownLatch;
        this.groupName = groupName;
        this.millis = millis;
    }

    @Override
    public void run() {
        try {
            logger.info(groupName + "开始处理业务!" + millis);
            Thread.sleep(millis);
            logger.info(groupName + "处理业务结束!" + millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            countDownLatch.countDown();//计数器减1
        }
    }
}

在这里插入图片描述

2.3、方案:Future & Callable

Future & Callable 使线程具有返回值的功能,其中future.get() 个是阻塞方法,通过调用所有future的get()来判断线程是否全部结束。

package com.wzl.xman.servicea.service.impl;

import com.wzl.xman.servicea.service.ThreadBizService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
public class ThreadBizServiceImpl implements ThreadBizService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private final static ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 2000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(500));
    
    @Override
    public void threadBizMethod03(String groupName) {
        logger.info(groupName + "==threadBizMethod Start==");
        List<Future> futures = new ArrayList<Future>();

        for (int i = 1; i <= 10; i++) {
            MyCallable runnable = new MyCallable(groupName, i * 1000);
            futures.add(executor.submit(runnable));
        }

        try {
            for (Future<?> future : futures) {
                String result = (String) future.get();//阻塞方法,获取线程返回结果
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        logger.info(groupName + "==threadBizMethod End==");
    }

}

/**
 * 线程处理类(带返回结果的)
 */
class MyCallable implements Callable<String> {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private long millis;
    private String groupName;

    public MyCallable(String groupName, long millis) {
        this.groupName = groupName;
        this.millis = millis;
    }

    @Override
    public String call() throws Exception {
        try {
            logger.info(groupName + "开始处理业务!" + millis);
            Thread.sleep(millis);
            logger.info(groupName + "处理业务结束!" + millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return groupName + "=" + millis;
    }
}

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值