目录
一、java用多线程来加快循环效率(推荐第3种!!!!)
第一种:线程池搭配闭锁
第二种:分页概念执行线程
第三种:分页概念执行线程进阶版!!!!
一、java用多线程来加快循环效率(推荐第3种!!!!)
第一种:线程池搭配闭锁
涉及知识:Executors(线程池)、CountDownLatch(闭锁)
优点:代码简洁,方便阅读,性能稳定;
缺点:Executors创建的线程池是公用的,如果多个地方使用这种循环多线程的方式,就会抢夺线程池资源,这样运行速度也会降低;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class test{
public static void main(String[] args) throws Exception {
/**
* 两个要点:
* 1.用Executors实现固定大小的线程池,从而达到控制硬件资源消耗的目的。
* 2.用CountDownLatch(闭锁),来确保循环内的多线程都执行完成后,再执行后续代码
*/
// 固定的线程池(当前线程池大小为5
final ExecutorService executor = Executors.newFixedThreadPool(5);
// 初始化数据
List<Map<String,Object>> list = new ArrayList<>();
for(int i=0;i<50;i++){
Map<String,Object> object = new HashMap<>();
object.put("index",i);
list.add(object);
}
// 初始化计时器
final CountDownLatch cdl = new CountDownLatch(list.size());
System.out.println("====== 线程开始 =====");
// 遍历
for(final Map<String,Object> object:list){
// 开启线程
executor.submit(new Runnable() {
@Override
public void run() {
try {
Thread t = Thread.currentThread();
String name = t.getName();
// 模拟运行耗时
Thread.sleep(500);
System.out.println(name+":执行到"+object.get("index"));
object.put("status","已经执行过");
} catch (InterruptedException e) {
e.printStackTrace();
}
// 闭锁-1
cdl.countDown();
}
});
}
// 调用闭锁的await()方法,该线程会被挂起,它会等待直到count值为0才继续执行
// 这样我们就能确保上面多线程都执行完了才走后续代码
cdl.await();
//关闭线程池
executor.shutdown();
System.out.println("====== 线程结束 =====");
// 校验多线程正确性
for(Map<String,Object> object:list){
System.out.println(object.get("index") + ":" + object.get("status"));
}
}
}
第二种:分页概念执行线程
涉及知识:CountDownLatch(闭锁)
优点:运行速度快;
缺点:代码阅读难;
public static void main(String[] args) throws InterruptedException {
/**
* 两个要点:
* 1.设定线程数量,用分页的概念,将集合拆分成若干组分批执行线程
* 2.用CountDownLatch(闭锁),来确保循环内的多线程都执行完成后,再执行后续代码
*/
// 初始化数据
final List<Map<String,Object>> list = new ArrayList<>();
for(int i=0;i<6;i++){
Map<String,Object> object = new HashMap<>();
object.put("index",i);
list.add(object);
}
int size = list.size(); //集合总数
int theadCount = 5; // 执行线程数量
int splitCount = size / theadCount + (size % theadCount != 0 ? 1 : 0); //计算分拆数量,向上取整
final CountDownLatch cdl = new CountDownLatch(size); //计数器
for (int i = 1; i <= theadCount; i++) {
final int beign = (i - 1) * splitCount;
final int end = (i * splitCount) > size ? size : i * splitCount;
if(beign >= end) break;
new Thread(new Runnable() {
@Override
public void run() {
for (int j = beign; j < end; j++) {
try {
Thread t = Thread.currentThread();
String name = t.getName();
// 模拟运行耗时
Thread.sleep(500);
Map<String, Object> object = list.get(j);
System.out.println(name+":执行到"+object.get("index"));
object.put("status","已经执行过");
} catch (InterruptedException e) {
e.printStackTrace();
}
// 闭锁-1
cdl.countDown();
}
}
}).start();
}
// 调用闭锁的await()方法,该线程会被挂起,它会等待直到count值为0才继续执行
// 这样我们就能确保上面多线程都执行完了才走后续代码
cdl.await();
System.out.println("====== 线程结束 =====");
// 校验多线程正确性
for(Map<String,Object> object:list){
System.out.println(object.get("index") + ":" + object.get("status"));
}
}
第三种:分页概念执行线程进阶版!!!!
涉及知识:CountDownLatch(闭锁)、对象封装;
优点:运行速度快,代码简洁优雅;
缺点:;
package com.xxx;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/***
* 多线程优化 by lyx 20230318
* 在循环里跑多线程,提高执行速度
*/
public class TheadMultis {
private Integer theadCount; //线程数量
private Integer size; //集合大小
private Integer timeOut = 60; //超时时间(单位:分钟)
private Function function; //执行方法
public interface Function {
void run(int i);
}
public TheadMultis(int theadCount, int size, Function function) {
this.theadCount = theadCount;
this.size = size;
this.function = function;
}
public TheadMultis(int theadCount, int timeOut, int size, Function function) {
this.theadCount = theadCount;
this.timeOut = timeOut;
this.size = size;
this.function = function;
}
public void start() throws InterruptedException,TheadMultisException {
int size = this.size; //集合总数
int theadCount = this.theadCount; // 执行线程数量
int splitCount = size / theadCount + (size % theadCount != 0 ? 1 : 0); //计算分拆数量,向上取整
final CountDownLatch cdl = new CountDownLatch(size); //计数器
for (int i = 1; i <= theadCount; i++) {
final int beign = (i - 1) * splitCount;
final int end = (i * splitCount) > size ? size : i * splitCount;
if(beign >= end) break;
new Thread(new Runnable() {
@Override
public void run() {
for (int j = beign; j < end; j++) {
try{
function.run(j);
}catch (Exception e){
e.printStackTrace();
}
// 闭锁-1
cdl.countDown();
}
}
}).start();
}
int time = this.timeOut != null ? this.timeOut : 60;
// 调用闭锁的await()方法,该线程会被挂起,它会等待直到count值为0才继续执行
// 这样我们就能确保上面多线程都执行完了才走后续代码
try{
if(!cdl.await(time, TimeUnit.MINUTES)){
throw new TheadMultisException("Executed for more than "+ time +" minutes");
}
}catch (InterruptedException e){
throw e;
}
}
public class TheadMultisException extends Exception{
public TheadMultisException() {
super();
}
public TheadMultisException(String s) {
super(s);
}
}
public static void main(String[] args) throws Exception {
// 初始化数据
final List<Map<String,Object>> list = new ArrayList<>();
for(int i=0;i<10;i++){
Map<String,Object> object = new HashMap<>();
object.put("index",i);
list.add(object);
}
new TheadMultis(2, 1,list.size(), new TheadMultis.Function() {
@Override
public void run(int i) {
Thread t = Thread.currentThread();
String name = t.getName();
// 模拟运行耗时
try {
// Thread.sleep(1000 * 60);
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
Map<String, Object> object = list.get(i);
System.out.println(name+":执行到"+object.get("index"));
object.put("status","已经执行过");
}
}).start();
System.out.println("====== 线程结束 =====");
// 校验多线程正确性
for(Map<String,Object> object:list){
System.out.println(object.get("index") + ":" + object.get("status"));
}
}
}