1. 程式人生 > >Java--如何使用多執行緒對一個HashSet進行平行計算

Java--如何使用多執行緒對一個HashSet進行平行計算

這段時間工作比較忙。今天抽空整理了一個多執行緒使用場景。

當處理一個數據量比較大的集合時(每個元素的計算都耗時比較長)。由於只使用一個執行緒進行計算比較慢。所以想到多跑幾個執行緒進行處理。

1.每個執行緒可以自行計算要處理集合的開始和結束索引,確保每一個元素都被計算的到。

2.同時為了防止這個集合中資料的長度有變化,需要執行緒每一次計算前都重新獲取集合長度,重新計算該執行緒要計算這個集合的開始和結束索引。

3.執行緒數是通過xml配置來進行修改的。不用每次修改程式碼來改動執行緒數。

程式碼如下:

Main:(主函式的類)

/**
 * 使用可配置的多個執行緒來對一個大資料量的集合進行計算,每個執行緒計算其中的一部分資料。 執行緒每隔一段時間根據資料集合計算自身要計算的索引。然後再做計算。
 * 
 * @author Stalin 2018年9月21日上午9:51:04
 */
public class Main {
	public static Set<String> set = new HashSet<>();
	public static int count;

	public static void main(String[] args) {

		// 為set新增10w條資料
		for (int i = 0; i < 100000; i++) {
			set.add("/home/test/dir" + i);
		}

		// 獲取執行緒總數量
		count = getCount();

		// 根據執行緒數建立足夠的執行緒
		for (int i = 1; i <= count; i++) {
			Timer t = new Timer(i);
			t.start();
			System.out.println("這是第" + i + "個執行緒,執行緒總數:" + count);
		}
	}

	// 獲取配置檔案中的執行緒數量
	public static int getCount() {
		int count = 1;
		SAXReader reader = new SAXReader();
		try {
			Document document = reader.read(new File("etc/config.xml"));
			Element root = document.getRootElement();
			count = Integer.valueOf(root.element("Config").elementText("ThreadCount"));
		} catch (Exception e) {
			e.printStackTrace();
			return count;
		}
		return count;
	}
}

Timer(計算執行緒):

public class Timer extends Thread {

	private int startIndex;
	private int endIndex;
	private int index;

	public int getStartIndex() {
		return startIndex;
	}

	public void setStartIndex(int startIndex) {
		this.startIndex = startIndex;
	}

	public int getEndIndex() {
		return endIndex;
	}

	public void setEndIndex(int endIndex) {
		this.endIndex = endIndex;
	}

	public int getIndex() {
		return index;
	}

	public void setIndex(int index) {
		this.index = index;
	}

	public Timer(int index) {// 根據傳入的執行緒號,可以計算出開始索引和結束索引
		this.index = index;
	}

	@Override
	public void run() {
		while (true) {
			List<String> timeList = new ArrayList<>();
			// 將set的全部元素新增到list當中
			timeList.addAll(Main.set);
			// 根據當前執行緒傳入的索引值計算要計算的開始索引和結束索引
			if (timeList.size() != 0) {
				startIndex = 1 + (Main.set.size() / Main.count * (index - 1));
				endIndex = 0 + (Main.set.size() / Main.count * index);
				if (index == Main.count) {// 最後一個執行緒,結束索引為set的最後一個下標。
					endIndex = Main.set.size() - 1;
				} else if (index == 1) {// 第一個執行緒,開始索引應該為0,
					startIndex = 0;
				}
				System.out.println("這是第:" + index + "個計算執行緒,開始索引/結束索引:" + startIndex + "/" + endIndex);
				// 進行計算
				int num = 0;
				for (int i = startIndex; i <= endIndex; i++) {
					if (timeList.get(i) != null) {
						num++;
					}
				}
				System.out.println("執行緒" + index + "計算了" + num + "個目錄");
			}
			try {
				Thread.sleep(10000L);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}

配置檔案如下:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
	<Config>
		<ThreadCount>5</ThreadCount>
	</Config>
</Root>

執行結果如下:

由於我只是舉個例子,沒有在這裡一直更新set的值,有興趣的朋友可以自己嘗試一下。也是可以的哦~~

喜歡的朋友點個贊哦~~