Java多线程如何保证线程池里的线程都执行完毕
背景:
项目中为了提高性能常常会引入多线程,当我们使用线程池时有时要满足“当线程池里的线程都执行完毕后才能进行下一步”这种业务场景,例如:当多线程操作一个文件时要保证所有线程都运行完毕才能保证文件的完整;当用多线程给一个对象的多个属性进行赋值时要保证线程都运行完毕才将此对象返回,否则就会出现对象属性不全。
实现方式:
1、使用isTerminated方法
2、使用CountDownLatch
3、使用awaitTermination方法
实现代码:
准备:
1、创建Phone对象,属性:color、price;
2、创建People对象,属性:name、age、Phone。
3、有个List<Phone>,里面有
phone1:red、1000;
phone2:blue、2000
phone3:black、3000
4、有个List<People>,里面有
zhangsan,20岁
lisi,21岁
wangwu,22岁
要求:
用多线程实现给zhangsan指定phone1、lisi指定phone2、wangwu指定phone3。
Phone:
public class Phone { //手机颜色 private String color; //手机价格 private double price; public Phone() { } public Phone(String color, double price) { this.color = color; this.price = price; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Phone{" + "color='" + color + '\'' + ", price=" + price + '}'; } }
People :
class People { private String name; private int age; private Phone phone; public People() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Phone getPhone() { return phone; } public void setPhone(Phone phone) { this.phone = phone; } @Override public String toString() { return "People{" + "name='" + name + '\'' + ", age=" + age + ", phone=" + phone + '}'; } }
CodeDemo:
public class CodeDemo { //创建线程池,核心线程数:2;最大线程数:4;时间:5;时间单位:秒;阻塞队列:ArrayBlockingQueue,最大容量为10;线程工厂:默认;拒绝策略:默认 static ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(2, 4, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10)); public static void main(String[] args) { //执行前准备 List<Phone> phones = getPhoneList(); List<People> peoples = getPeopleList(); //使用isTerminated方法 executorThreads1(peoples, phones); //使用CountDownLatch // executorThreads2(peoples, phones); //使用awaitTermination方法 // executorThreads3(peoples, phones); //结束验证赋值是否成功 peoples.forEach(people -> System.out.println(people)); } /** * 使用awaitTermination方法: * 当使用awaitTermination时,主线程会处于一种等待的状态,有下面两种情况发生时才会解除等待状态 * 1、等待线程池中所有的线程都运行完毕后会解除等待,继续运行 * 2、如果到了设置的超时时间,线程即使没运行完也会解除等待,继续运行 */ private static void executorThreads3(List<People> peoples, List<Phone> phones) { peoples.forEach(people -> { poolExecutor.execute(new Runnable() { @Override public void run() { // System.out.println("当前线程:" + Thread.currentThread().getName()); phones.forEach(phone -> { if ("zhangsan".equals(people.getName()) && "red".equals(phone.getColor())) { people.setPhone(phone); } else if ("lisi".equals(people.getName()) && "blue".equals(phone.getColor())) { people.setPhone(phone); } else if ("wangwu".equals(people.getName()) && "black".equals(phone.getColor())) { people.setPhone(phone); } }); //每个线程暂停1S,防止代码运行太快看不出多线程效果 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }); }); poolExecutor.shutdown(); try { //参数:超时时间、时间单位 poolExecutor.awaitTermination(1, TimeUnit.MINUTES); } catch (InterruptedException e) { e.printStackTrace(); } } private static void executorThreads2(List<People> peoples, List<Phone> phones) { CountDownLatch count = new CountDownLatch(peoples.size()); peoples.forEach(people -> { poolExecutor.execute(new Runnable() { @Override public void run() { // System.out.println("当前线程:" + Thread.currentThread().getName()); phones.forEach(phone -> { if ("zhangsan".equals(people.getName()) && "red".equals(phone.getColor())) { people.setPhone(phone); } else if ("lisi".equals(people.getName()) && "blue".equals(phone.getColor())) { people.setPhone(phone); } else if ("wangwu".equals(people.getName()) && "black".equals(phone.getColor())) { people.setPhone(phone); } }); //每个线程暂停1S,防止代码运行太快看不出多线程效果 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count.countDown(); } }); }); poolExecutor.shutdown(); //await():等待所有count都执行完毕 try { count.await(); } catch (InterruptedException e) { e.printStackTrace(); } } private static void executorThreads1(List<People> peoples, List<Phone> phones) { peoples.forEach(people -> { //多线程运行 poolExecutor.execute(new Runnable() { @Override public void run() { // System.out.println("当前线程:" + Thread.currentThread().getName()); phones.forEach(phone -> { if ("zhangsan".equals(people.getName()) && "red".equals(phone.getColor())) { people.setPhone(phone); } else if ("lisi".equals(people.getName()) && "blue".equals(phone.getColor())) { people.setPhone(phone); } else if ("wangwu".equals(people.getName()) && "black".equals(phone.getColor())) { people.setPhone(phone); } }); //每个线程暂停1S,防止代码运行太快看不出多线程效果 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }); }); poolExecutor.shutdown(); //每隔1s检测是否线程池里的线程都执行完毕,都执行完后才往下继续运行否则一直卡在这里 while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if (poolExecutor.isTerminated()) break; } } private static List<Phone> getPhoneList() { ArrayList<Phone> phones = new ArrayList<>(); //创建phone1 phones.add(new Phone("red", 1000)); //创建phone2 phones.add(new Phone("blue", 2000)); //创建phone3 phones.add(new Phone("black", 3000)); return phones; } private static List<People> getPeopleList() { ArrayList<People> peoples = new ArrayList<>(); //创建people1 People people1 = new People(); people1.setName("zhangsan"); people1.setAge(20); peoples.add(people1); //创建people2 People people2 = new People(); people2.setName("lisi"); people2.setAge(21); peoples.add(people2); //创建people3 People people3 = new People(); people3.setName("wangwu"); people3.setAge(22); peoples.add(people3); return peoples; } }