经过多线程的学习和实践 总结了两种多线程查表方法
两种方法都经过我的封装 某表使用时 server层加上方法sql即可
查询流程:
1 count全表条数
2 通过总条数 将全表数据分为10份
3 开辟10个线程查询limit语句(线程数可自定义)
以下方法均以mysql数据库测试 其他库同理
目录
一 线程池方法
二 @Async注解方法
一 线程池方法
controller层
int totalNum = testService.countNum(new testTable());
//重写多线程中引用的方法
List<T> threadHandle = ThreadPoolUtils.threadPool(totalNum, new ThreadTableDataQuery() {
@Override
public List<T> selectTableData(Integer page, Integer limit) throws Exception {
return testService.selectTableData(page, limit);
}
});
//lambda表达式写法
//List<T> threadHandle = ThreadPoolUtils.threadPool(totalNum, (page, limit) -> testService.selectTableData(page, limit));
//转换为list对象
List<TestTable> test= JSON.parseArray(JSON.toJSONString(threadHandle), testTable.class);
当数据量多时 JSON.parseArray和JSON.toString转换方法较慢
下篇文章我再介绍下泛型List转List对象(Json转换工具类)https://blog.csdn.net/weixin_56567361/article/details/128116842
java反射方式和强转方法比阿里巴巴fastJson方式快了40多倍
ThreadPoolUtils
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;
/**
* 多线程查全表通用工具类
*/
public class ThreadPoolUtils {
/**
* 定义十个线程
*/
private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
/**
* 多线程查全表(通用)
* ThreadPoolExecutor线程池方法
*
* @param totalNum 总条数
* @param threadTableDataQuery 查询方法(需要新建接口类)
* @return
*/
public static List<T> threadPool(int totalNum, ThreadTableDataQuery threadTableDataQuery) throws Exception {
//将ArrayList转换为线程安全的SynchronizedList
List<T> result = Collections.synchronizedList(new ArrayList<>(NumberUtils.arrayListRightSize(totalNum)));
// List<T> result = new CopyOnWriteArrayList<>();
//数据量超出10 即使用线程异步处理
if (totalNum > 10) {
//将数据分组 分成10份 计算每份的条数
int remainder = totalNum % 10;
int size = remainder > 0 ? totalNum / 10 + 1 : totalNum / 10;
CountDownLatch downLatch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
int page = i * size;
executor.submit(() -> {
try {
result.addAll(threadTableDataQuery.selectTableData(page, size));
} catch (Exception e) {
e.printStackTrace();
} finally {
downLatch.countDown();
}
});
}
try {
downLatch.await();
} catch (Exception e) {
e.printStackTrace();
}
} else {
result.addAll(threadTableDataQuery.selectTableData(0, 10));
}
return result;
}
}
ThreadTableDataQuery接口
import org.apache.poi.ss.formula.functions.T;
import java.util.List;
public interface ThreadTableDataQuery {
/**
* 线程池接口类 查询方法
*
* @param page
* @param limit
* @return
* @throws Exception
*/
public List<T> selectTableData(Integer page, Integer limit) throws Exception;
}
interface接口
/**
* 泛型查询
*
* @param page
* @param limit
* @return
*/
public List<T> selectTableData(Integer page, Integer limit);
server层
/**
* 泛型查询
*
* @param page
* @param limit
* @return
*/
public List<T> selectTableData(Integer page, Integer limit);
impl层
/**
* 泛型查询
*
* @param page
* @param limit
* @return
*/
@Override
public List<T> selectTableData(Integer page, Integer limit) {
return testMapper.selectTableData(page,limit);
}
mapper层
import org.apache.ibatis.annotations.Param;
/**
* 泛型查询
*
* @param
* @return
*/
public List<T> selectTableData(@Param("page") Integer page,
@Param("limit") Integer limit);
xml文件
<select id="selectTableData" parameterType="..." resultMap="...">
select id, test, name from test_table
<if test="page != null">limit #{page},#{limit}</if>
</select>
二 @Async注解方法
controller层
int totalNum = testService.countNum(new testTable());
//重写多线程中引用的方法
List<T> threadAsync = ThreadPoolUtils.threadAsync(totalNum, new ThreadAsyncTableDataQuery() {
@Override
public Future<List<T>> selectTableDataAsync(Integer page, Integer limit) throws Exception {
return testService.selectTableDataAsync(page, limit);
}
});
//lambda表达式写法
//List<T> threadAsync = ThreadPoolUtils.threadAsync(totalNum, (page, limit) -> testService.selectTableDataAsync(page, limit));
//转换为list对象
List<TestTable> test= JSON.parseArray(JSON.toJSONString(threadAsync), testTable.class);
调用方法和上面线程池方法类似
ThreadPoolUtils
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;
/**
* 多线程查全表通用工具类
*/
public class ThreadPoolUtils {
/**
* 多线程查全表(通用)
* 注解@Async线程方法
*
* @param totalNum
* @param threadAsyncTableDataQuery
* @return
* @throws Exception
*/
public static List<T> threadAsync(int totalNum, ThreadAsyncTableDataQuery threadAsyncTableDataQuery) throws Exception {
List<Future<List<T>>> list = new ArrayList<>();
if (totalNum > 10) {
int remainder = totalNum % 10;
int size = remainder > 0 ? totalNum / 10 + 1 : totalNum / 10;
for (int i = 0; i < 10; i++) {
int page = i * size;
Future<List<T>> pv = threadAsyncTableDataQuery.selectTableDataAsync(page, size);
list.add(pv);
}
} else {
Future<List<T>> ts = threadAsyncTableDataQuery.selectTableDataAsync(0, 10);
list.add(ts);
}
return ThreadPoolUtils.taskValue(list);
}
/**
* 拿取线程里的数据
*
* @param taskFutures
* @return
*/
public static List<T> taskValue(List<Future<List<T>>> taskFutures) {
List<T> result = new ArrayList<>();
try {
for (Future<List<T>> future : taskFutures) {
List<T> obj = future.get();
if (null != obj) {
result.addAll(obj);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
ThreadAsyncTableDataQuery接口
import org.apache.poi.ss.formula.functions.T;
import java.util.List;
import java.util.concurrent.Future;
public interface ThreadAsyncTableDataQuery {
/**
* 注解多线程接口类 查询方法
*
* @param page
* @param limit
* @return
* @throws Exception
*/
public Future<List<T>> selectTableDataAsync(Integer page, Integer limit) throws Exception;
}
server层
/**
* 注解多线程泛型查询
*
* @param page
* @param limit
* @return
*/
public Future<List<T>> selectTableDataAsync(Integer page, Integer limit);
impl层
核心注解:@Async
不加就相当于普通循环查
import org.springframework.scheduling.annotation.Async;
import java.util.concurrent.Future;
/**
* 注解多线程泛型查询
*
* @param page
* @param limit
* @return
*/
@Async
@Override
public Future<List<T>> selectTableDataAsync(Integer page, Integer limit) {
List<T> ts = testMapper.selectTableDataAsync(page,limit);
return new AsyncResult<>(ts);
}
mapper层
import org.apache.ibatis.annotations.Param;
/**
* 注解多线程泛型查询
*
* @param
* @return
*/
public List<T> selectTableDataAsync(@Param("page") Integer page,
@Param("limit") Integer limit);
xml文件
<select id="selectTableDataAsync" parameterType="..." resultMap="...">
select id, test, name from test_table
<if test="page != null">limit #{page},#{limit}</if>
</select>
启动程序
加上@EnableAsync注解
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* 启动程序
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@EnableAsync
public class RuoYiApplication
{
public static void main(String[] args)
{
SpringApplication.run(RuoYiApplication.class, args);
}
速度测试
两种多线程方法都已介绍完 相比之下@Async更简便 容易理解些
现在上个测试图 看下速度
数据量约18w条
mybatis-plus耗时:3574ms
线程池方法耗时:541ms
注解多线程耗时:467ms
十次分割limit耗时:3259ms
单个sql耗时:1171ms
测试发现 两种多线程方法都比普通的sql查询快了一倍 当数据越多时 线程优势越明显
最后 两种封装的多线程查表方法就讲到这里啦文章来源:https://www.toymoban.com/news/detail-654096.html
如果写的有什么问题 或大家有什么有疑问 欢迎评论区讨论哦😇 文章来源地址https://www.toymoban.com/news/detail-654096.html
到了这里,关于Java多线程查表(封装方法 多表通用)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!