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;
}
}
}