Javaスレッドプールを使用したビッグデータ量統計タスク
2750 ワード
最近では、毎週生成されるログ・テーブルを処理し、結果を別のテーブルに出力する必要があります.ログ表は300万も少なく、数千万件の記録がある.そこでマルチスレッドでデータを処理するつもりです.スレッドプールを使用する場合、いくつかの注意点があります.
1、入り口のところで、直接新しいスレッドを実行して、それから結果を返して、それからログ表を通じて追跡します;
2、独立したスレッド名規則を設定し、自動的に生成されたスレッド名を区別する.
3、直接ThreadPoolExecutorを使用し、Executorsクラスを借りて生成するのではなく、
4、Futureのブロック特性を利用して、全スレッドの実行が終了した時点を制御する.
5、実行を中断するメカニズムを増やす必要があるかどうかを考慮する.
6、ロット操作ができる場所を考えてできるだけロット操作を合成する.
コード参照:
期間中にデッドロックの問題(org.springframework.dao.D e a d lockLoserDataAccessException:PreparedStatementCallback;SQL[INSERT IGNORE INTO tb(…)VALUES (..)]; Deadlock found when trying to get lock; try restarting transaction;),もともとロット初期で性能を向上させたいと思っていましたが、テーブルが更新されたときに、同じローレコードをロックすると、確かにデッドロックが発生しやすく、あまり良い方法はなく、ビジネスロジック上、このようなマルチスレッド競合を回避するために適切な調整が必要になる可能性があることを説明し、設計の最適化を優先して競合を解決します.
1、入り口のところで、直接新しいスレッドを実行して、それから結果を返して、それからログ表を通じて追跡します;
2、独立したスレッド名規則を設定し、自動的に生成されたスレッド名を区別する.
3、直接ThreadPoolExecutorを使用し、Executorsクラスを借りて生成するのではなく、
4、Futureのブロック特性を利用して、全スレッドの実行が終了した時点を制御する.
5、実行を中断するメカニズムを増やす必要があるかどうかを考慮する.
6、ロット操作ができる場所を考えてできるだけロット操作を合成する.
コード参照:
//1.
int threadNum = totalCount / StatConstant.SPLIT_NUM;
if (threadNum * StatConstant.SPLIT_NUM < totalCount) {
threadNum++;
}
//2.
List> futureList = new ArrayList<>();
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat("LogHandlerThread-%d")
.build();
ExecutorService executorService = new ThreadPoolExecutor(threadNum, threadNum, 0L, TimeUnit.SECONDS, new ArrayBlockingQueue(threadNum), threadFactory);
for (int i = 0; i < threadNum; i++) {
int begin = i * StatConstant.SPLIT_NUM;
int end = (i + 1) * StatConstant.SPLIT_NUM;
if (i == threadNum - 1) {
end = totalCount;
}
Future future = executorService.submit(new LogHandlerThread(begin, end, weekNo, applicationContext));
futureList.add(future);
}
//3.
boolean finalResult = true;
for (int i = 0; i < futureList.size(); i++) {
try {
Future future = futureList.get(i);
Integer result = future.get();
handleCount += ((result == null) ? 0 : result);
} catch (Exception e) {
weekLog.setMessage(weekLog.getMessage() + "###" + "(ThreadNum=" + i + ")" + e.getMessage());
finalResult = false;
}
}
executorService.shutdown();
//4. ...
public class LogHandlerThread implements Callable {
public LogHandlerThread(Integer begin, Integer end, String weekNo, ApplicationContext applicationContext) {
// ..
}
@Override
public Integer call() {
// ..
}
}
期間中にデッドロックの問題(org.springframework.dao.D e a d lockLoserDataAccessException:PreparedStatementCallback;SQL[INSERT IGNORE INTO tb(…)VALUES (..)]; Deadlock found when trying to get lock; try restarting transaction;),もともとロット初期で性能を向上させたいと思っていましたが、テーブルが更新されたときに、同じローレコードをロックすると、確かにデッドロックが発生しやすく、あまり良い方法はなく、ビジネスロジック上、このようなマルチスレッド競合を回避するために適切な調整が必要になる可能性があることを説明し、設計の最適化を優先して競合を解決します.