我的問題是如何正確地為這個任務實作多執行緒。
我有一個程式需要很長時間才能完成執行。大約一個半小時。我需要生成大約 10,000 個隨機且唯一的數字代碼。下面的代碼是我第一次實作它并立即擁有它的方式。
import java.util.Random;
import java.util.ArrayList;
public class Main
{
public static void main(String[] args) {
Random random = new Random();
// This holds all the codes
ArrayList<String> database = new ArrayList<>();
int counter = 0;
while(counter < 10000){
// Generate a 10 digit long code and append to sb
StringBuilder sb = new StringBuilder();
for(int i = 0; i < 10; i ){
sb.append(random.nextInt(10));
}
String code = String.valueOf(sb);
sb.setLength(0);
// Check if this code already exists in the database
// If not, then add the code and update counter
if(!database.contains(code)){
database.add(code);
counter ;
}
}
System.out.println("Done");
}
}
這當然是非常低效的。所以我的問題是:有沒有一種方法可以在這段代碼上實作多執行緒?我能說的最好的方法是給兩個核心/執行緒相同的代碼,但讓它們都檢查一個 ArrayList?兩個核心/執行緒都會生成代碼,但會檢查以確保它剛剛生成的代碼不存在于其他核心/執行緒或自身。我在下面畫了一個粗略的圖表。非常感謝任何見解、建議或指示。

uj5u.com熱心網友回復:
使用更合適的資料結構和更合適的資料表示,這也應該更快更容易閱讀:
Set<Long> database = new HashSet<>(10000);
while(database.size() < 10000){
database.add(ThreadLocalRandom.current().nextLong(10_000_000_000L);
}
uj5u.com熱心網友回復:
從更明顯的優化開始:
- 不使用
ArrayList,使用HashSet。ArrayListcontains()時間復雜度為 O(n),而 HashSet 為 O(1)。閱讀這個關于Java 集合框架的 Big O 摘要的問題。閱讀大 O 表示法。 - 使用適當的初始容量初始化您的集合。對于您的情況,這將是:
new HashSet<>(10000);
像這樣的底層陣列不會被復制以增加它們的容量。我建議查看/除錯 java 集合的實作,以更好地了解它們是如何作業的。甚至嘗試自己實作它們。
在深入研究復雜的多執行緒優化之前,先解決簡單的問題——比如錯誤的集合選擇。
編輯:根據@Thomas 在評論中的建議,您可以直接在您需要的范圍內生成一個數字(長) - 0 到 9_999_999_999。您可以在這個問題中看到如何做到這一點。將結果數字字串化,如果長度小于 10,則用前導零填充。
uj5u.com熱心網友回復:
示例:(使用 ConcurrentHashMap,使用執行緒,使用 random.nextLong())
public class Main {
static Map<String,Object> hashMapCache = new ConcurrentHashMap<String,Object>();
public static void main(String[] args) {
Random random = new Random();
// This holds all the codes
ArrayList<String> database = new ArrayList<>();
int counter = 0;
int NumOfThreads = 20;
int total = 10000;
int numberOfCreationsForThread = total/NumOfThreads;
int leftOver = total%NumOfThreads;
List<Thread> threadList = new ArrayList<>();
for(int i=0;i<NumOfThreads;i ){
if(i==0){
threadList.add(new Thread(new OneThread(numberOfCreationsForThread leftOver,hashMapCache)));
}else {
threadList.add(new Thread(new OneThread(numberOfCreationsForThread,hashMapCache)));
}
}
for(int i=0;i<NumOfThreads;i ){
threadList.get(i).start();;
}
for(int i=0;i<NumOfThreads;i ){
try {
threadList.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(String key : hashMapCache.keySet()){
database.add(key);
}
System.out.println("Done");
}}
單執行緒:
public class OneThread implements Runnable{
int numberOfCreations;
Map<String,Object> hashMapCache;
public OneThread(int numberOfCreations,Map<String,Object> hashMapCache){
this.numberOfCreations = numberOfCreations;
this.hashMapCache = hashMapCache;
}
@Override
public void run() {
int counter = 0;
Random random = new Random();
System.out.println("thread " Thread.currentThread().getId() " Start with " numberOfCreations);
while(counter < numberOfCreations){
String code = generateRandom(random);
while (code.length()!=10){
code = generateRandom(random);
}
// Check if this code already exists in the database
// If not, then add the code and update counter
if(hashMapCache.get(code)==null){
hashMapCache.put(code,new Object());
counter ;
}
}
System.out.println("thread " Thread.currentThread().getId() " end with " numberOfCreations);
}
private static String generateRandom(Random random){
return String.valueOf(digits(random.nextLong(),10));
}
/** Returns val represented by the specified number of hex digits. */
private static String digits(long val, int digits) {
val = val > 0 ? val : val*-1;
return Long.toString(val).substring(0,digits);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/447423.html
