多線程排序


import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SortMain {

public static void main(String[] args) throws Exception{
Integer threadNumber = 4; //線程數量
Integer stopNumber = threadNumber; //閉合器數量
Integer randomCount = 50; //隨機數數量
Integer randomNumber = 50; //隨機數范圍
List<Integer> workSpeace = new ArrayList<>(); //每個線程需要工作的量 list的長度與線程量一樣
if(randomCount % threadNumber == 0){
for(int i=0; i < threadNumber; i ++){
workSpeace.add(randomCount/threadNumber);
}
}else{
Integer itemValue = randomCount/threadNumber;
for(int i = 0 ; i < threadNumber ; i ++){
if(i == threadNumber -1){
workSpeace.add((randomCount-(itemValue*threadNumber)) + itemValue);
}else{
workSpeace.add(itemValue);
}
}
}
CountDownLatch countDownLatch = new CountDownLatch(stopNumber); //閉合器子線程閉合器

CountDownLatch countDownLatchMain = new CountDownLatch(stopNumber); //主線程閉合器

ExecutorService executors = Executors.newFixedThreadPool(threadNumber); //線程池
Lock lock = new ReentrantLock();
List<Integer> arrayList = new ArrayList<>();
Random random = new Random(System.currentTimeMillis());
try {
for(int i=0; i < randomCount ; i++){
arrayList.add(random.nextInt(randomNumber));
}
System.out.println("隨機數集合:"+arrayList +" 長度:"+arrayList.size());
Map<Integer, String> thradValueMap = Collections.synchronizedMap(new HashMap());
Map<Integer, List<Integer>> mainValueMap = Collections.synchronizedMap(new HashMap());
List countSizeListValue = new ArrayList(); //
for(int i =0; i <threadNumber; i ++){
int finalI = i;
executors.execute(new Runnable() {
@Override
public void run(){
List<Integer> paramsList = new ArrayList(); //每個線程工作的內容
//思路:每個線程干10個值,10個線程干100個值
int startIndex; //沒個線程工作的10個值的尾坐標,也是沒個線程管理數值的結束 //startIndex endThreadIndex 因為for循環是反着的,所以這個值也是反着的
int endThreadIndex; //沒個線程工作的10個值的頭坐標,也是沒個線程管理數值的開始
endThreadIndex = ((randomCount/threadNumber)*finalI);
if(finalI == threadNumber-1){
startIndex = ((randomCount - ((randomCount/threadNumber)*finalI)) + endThreadIndex) -1;
}else{
startIndex = endThreadIndex + ((randomCount/threadNumber)-1);
}
for(int forStartIndex = startIndex; forStartIndex >= endThreadIndex; forStartIndex--){
paramsList.add(arrayList.get(forStartIndex)); //通過循環拿到每個線程需要工作的內容
}
//由於已知隨機數最大的值是100,所以可以很容易的規范沒個線程所管理的值范圍,在這里暫定 1號線程工作范圍為0-10.2號線程為11-20,以此類推
//start 此代碼塊規定此線程管理值的區間
int theManageValueMax;
int theManageValueMin;
if(finalI == threadNumber-1){//9
theManageValueMax = startIndex+1;
theManageValueMin = endThreadIndex;
}else{
theManageValueMax = startIndex;
theManageValueMin = endThreadIndex;
}
List<Integer> discardValue = new ArrayList<>(); //需要剔除的值的集合
for(int chickIndex = 0; chickIndex < workSpeace.get(finalI); chickIndex++){ //循環判斷每個線程需要工作內容值
Integer workValue = paramsList.get(chickIndex); //每個線程工作的基本單位(數值)
if(theManageValueMin <= workValue&&workValue <= theManageValueMax){
//如果符合工作數值區間,則什么都不做;
continue;
}else{ //如果不符合工作區間,則剔除到公共區域
Integer thisNumberParent = -1;
try {
lock.lockInterruptibly();
thisNumberParent = chickNumberParent(threadNumber, randomNumber, workValue); //調用此方法判斷此隨機數屬於哪個線程的工作區間
}catch (Exception e){
for(StackTraceElement itemError : e.getStackTrace()){
System.out.println(itemError);
}
}finally {
lock.unlock();
}
String theValueByMap = thradValueMap.get(thisNumberParent);
if(theValueByMap == null || "".equals(theValueByMap)){
thradValueMap.put(thisNumberParent,workValue.toString());
}else{
thradValueMap.put(thisNumberParent,theValueByMap + ","+workValue.toString());
}
discardValue.add(workValue);
}
}
for(Integer itemDiscardvalue :discardValue){
paramsList.remove(new Integer(itemDiscardvalue.intValue()));
}
countDownLatch.countDown();
try {
countDownLatch.await();
String thisThreadWorkValue = thradValueMap.get(finalI); //當所有子線程工作完之后 從公共區域拿出本應該屬於自己的值
if(thisThreadWorkValue == null || "".equals(thisThreadWorkValue)){ //如果公共區域沒有屬於自己的工作值

}else {
String thisThreadWorkValueSz[] = thisThreadWorkValue.split(",");
for(int i=0; i < thisThreadWorkValueSz.length; i++){
paramsList.add(Integer.valueOf(thisThreadWorkValueSz[i]));
}
paramsList = sortInt(paramsList);
}
mainValueMap.put(finalI,paramsList);
}catch (Exception e){
e.fillInStackTrace();
}finally {
countDownLatchMain.countDown();
}
// System.out.println("分割線---------------------------------");
}
});
}
countDownLatchMain.await();
List<Integer> finalList = new ArrayList<>();
for(int i =0; i<threadNumber; i++){
List<Integer> itemList = mainValueMap.get(i);
if(itemList == null || itemList.isEmpty()){
continue;
}
for(Integer itemValue : itemList){
finalList.add(itemValue);
}
}
System.out.println("排序好的值:"+finalList+" 長度:"+finalList.size());
arrayList.removeAll(finalList);
System.out.println("差集為:"+arrayList);
}catch (Exception e){
for(StackTraceElement itemError :e.getStackTrace()){
System.out.println(itemError);
}
}finally {
executors.shutdownNow();
}

}


/**
*
* @param paramsList 每個線程要干的事情...排序
* @return
*/
private static List<Integer> sortInt(List<Integer> paramsList){
List<Integer> resutList = new LinkedList<>();
for(int paramsListIndex = 0 ; paramsListIndex <paramsList.size(); paramsListIndex++){
if(resutList.size() == 0){
resutList.add(paramsList.get(paramsListIndex));
continue;
}
for(int resultListIndex = resutList.size(); resultListIndex >= 0 ; resultListIndex--){
if(resultListIndex == 0){
resutList.add(resultListIndex,paramsList.get(paramsListIndex));
break;
}
int paramsListInt = paramsList.get(paramsListIndex).intValue();
int resultListInt = resutList.get(resultListIndex-1).intValue();
if(paramsListInt <= resultListInt){
continue;
}else{
resutList.add(resultListIndex,paramsList.get(paramsListIndex));
break;
}
}
}

return resutList;
}

/**
* 判斷該數值在map中的key應該是多少
* @param threadNumber 線程量
* @param randomNumber 隨機數范圍
* @param needChickNumber 需要判斷的值
* @return
*/
private static Integer chickNumberParent(Integer threadNumber,Integer randomNumber,Integer needChickNumber){
Integer onlyThreadNumber = randomNumber/threadNumber; //單個線程負責值得區間, 比如 93個隨機數 6個線程, 那么93/6 就是前五個的線程負責量,余數是最后一個線程負責量
Integer valueIndex = needChickNumber / onlyThreadNumber; //還以上一行注釋為例子, 如果現在需要判斷93這個值屬於哪個線程的工作區間,則 93/(隨機數數量/線程量) 93/15 = 6, 因為線程量一共為6,在list中長度最大值為5(因為list坐標從0開始),所以93這個值屬於最后一個線程的工作區間
if(valueIndex >= threadNumber){
return valueIndex-1;
}else{
return valueIndex;
}
}


}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM