在java.util.concurrent学习(五-2) ExecutorCompletionService扩展有序的SortedExecutorCompletionService中对ExecutorCompletionService进行扩展后,有一些不足,这里进行优化。
不足点
- 构造函数中BlockingQueue completionQueue并未得到实际的使用,在这个版本中会将其删除
- 获取结果的方法需要制定单线程获取超时时间,这个参数有可能会被认为是获取所有结果的总超时时间,在这个版本中将这两个参数放入构造函数中,避免歧义。
- 上个版本只支持按照提交顺序获取结果,并不支持自定义排序方式,在这个版本中会增加一个构造参数Comparator<? super V> c来自定义排序方式。
新版本代码
package com.tangjianghua.juc.threadpool.extend;
import java.util.*;
import java.util.concurrent.*;
/**
* 扩展ExecutorCompletionService
* 构造函数可指定
*
* {@link Executor} 必填 executor 线程池
* 真正执行线程的线程池,装饰器模式
*
* {@link Long} timeout 必填 单线程获取超时时间
*
* {@link TimeUnit} timeUnit 必填 单线程获取超时单位
*
* {@link Comparator} c 排序方式
* 可指定结果的排序方式,当该变量为null时,可通过getAllSortedResult来获取线程执行结果,此时结果为提交时的顺序。
* 通过getAllResult获取无序的线程池执行结果。
*
* @auth tangjianghua
* @date 2021/6/15
*/
public class SortedExecutorCompletionService<V> extends ExecutorCompletionService {
/**
* 指定排序方式
*/
private Comparator<? super V> c;
/**
* 单线程获取超时时间
*/
private Long timeOut;
/**
* 单线程获取超时单位
*/
private TimeUnit timeUnit;
/**
* 当前下角标
*/
private int index;
/**
* 位置映射
* future -> index
*/
private Map<Future<V>, Integer> sortedMap = new HashMap<>();
/**
* 位置映射
* v -> index
*/
private Map<V, Integer> vSortedMap = new HashMap<>();
/**
* 是否已经排序
*/
private boolean sorted;
/**
* 结果集
* 如果sorted=true,则该结果集为已排序的结果集
*/
private volatile List<V> result = null;
/**
* 结果集锁
*/
private Object lock = new Object();
/**
* 是否已排序
*
* @return
*/
public boolean isSorted() {
return sorted;
}
public SortedExecutorCompletionService(Executor executor, Long timeOut, TimeUnit timeUnit) {
super(executor);
this.timeOut = timeOut;
this.timeUnit = timeUnit;
}
/**
* @param executor
* @param c 排序方式
*/
public SortedExecutorCompletionService(Executor executor, Long timeOut, TimeUnit timeUnit, Comparator<? super V> c) {
super(executor);
this.timeOut = timeOut;
this.timeUnit = timeUnit;
this.c = c;
}
@Override
public Future submit(Callable task) {
Future future = super.submit(task);
sortedMap.put(future, index++);
return future;
}
/**
* 获取排好序的结果
*
* @return 已排序返回 List<V>
* 未排序但已获取结果
*/
public List<V> getAllSortedResult() {
if (result == null) {
synchronized (lock) {
if (result == null) {
if (c != null) {
result = new ArrayList<>(index);
for (int i = 0; i < index; i++) {
try {
Future<V> future = super.poll(timeOut, timeUnit);
if (future != null) {
V v = future.get();
result.add(v);
vSortedMap.put(v, sortedMap.get(future));
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
result.sort(c);
} else {
Object[] arrayList = new Object[index];
for (int i = 0; i < index; i++) {
try {
Future<V> future = super.poll(timeOut, timeUnit);
if (future != null && null != future.get()) {
V v = future.get();
arrayList[sortedMap.get(future)] = v;
vSortedMap.put(v, sortedMap.get(future));
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
result = new ArrayList<>();
Arrays.stream(arrayList)
.filter(Objects::nonNull)
.forEach(o -> result.add((V) o));
this.sorted = true;
}
}
}
}
//未排序 但已获取过结果
//将已获取过结果的任务重新排序
if (!sorted) {
synchronized (lock) {
if (!sorted) {
if (c != null) {
if (result != null) {
result.sort(c);
}
} else {
Object[] arrayList = new Object[vSortedMap.size()];
vSortedMap.entrySet().stream()
.forEach(vIntegerEntry -> arrayList[vIntegerEntry.getValue()] = vIntegerEntry.getKey());
result = new ArrayList<>();
Arrays.stream(arrayList)
.filter(Objects::nonNull)
.forEach(o -> result.add((V) o));
}
}
sorted = true;
}
}
return result;
}
/**
* 获取未排序的结果
*
* @param timeOut
* @param timeUnit
* @return
*/
public List<V> getAllResult(Long timeOut, TimeUnit timeUnit) {
if (result == null) {
synchronized (lock) {
if (result == null) {
result = new ArrayList<>(index);
for (int i = 0; i < index; i++) {
try {
Future<V> future = super.poll(timeOut, timeUnit);
if (future != null && null != future.get()) {
V v = future.get();
result.add(v);
vSortedMap.put(v, sortedMap.get(future));
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
}
return result;
}
}
使用案例
使用线程池将User按顺序返回。
- user
package com.tangjianghua.juc.threadpool.extend;
/**
* @auth tangjianghua
* @date 2021/7/2
*/
public class User {
private String userName;
private int age;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
}
- test
package com.tangjianghua.juc.threadpool.extend;
import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;
import java.util.*;
import java.util.concurrent.*;
/**
* @auth tangjianghua
* @date 2021/6/15
*/
public class SortedExecutorCompletionServiceTest{
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100));
SortedExecutorCompletionService<User> sortedExecutorCompletionService = new SortedExecutorCompletionService<>(threadPoolExecutor,10L, TimeUnit.SECONDS,(o1, o2) -> o2.getAge()-o1.getAge());
for (int i = 0; i < 100; i++) {
User user = new User();
user.setAge(i);
user.setUserName(i+"");
sortedExecutorCompletionService.submit(() -> user);
}
// List list = sortedExecutorCompletionService.getAllResult(10L, TimeUnit.SECONDS);
// list.stream().forEach(System.out::println);
List allSortedResult = sortedExecutorCompletionService.getAllSortedResult();
allSortedResult.stream().forEach(System.out::println);
threadPoolExecutor.shutdown();
}
}
工具类
另外提供了一个工具类,虽然用起来比较蹩脚,但每个人的编码习惯不同,谁知道呢。
package com.tangjianghua.juc.util;
import com.tangjianghua.juc.threadpool.extend.SortedExecutorCompletionService;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
/**
* @auth tangjianghua
* @date 2021/7/2
*/
public class ThreadExecutorUtils {
/**
* 批量提交
*
* @param executor 线程池
* @param time 单线程获取超时时间 单位毫秒
* @param list 线程集合
* @param <T>
* @return
*/
public static <T> List<T> submit(Executor executor, Long time, List<? extends Callable> list) {
if (list != null && !list.isEmpty()) {
SortedExecutorCompletionService<T> completionService = new SortedExecutorCompletionService<>(executor, time, TimeUnit.MILLISECONDS);
list.stream()
.forEach(completionService::submit);
return completionService.getAllSortedResult();
}
return Collections.EMPTY_LIST;
}
/**
* 批量提交
*
* @param executor 线程池
* @param time 单线程获取超时时间 单位毫秒
* @param list 线程集合
* @param c 排序方式
* @param <T>
* @return
*/
public static <T> List<T> submit(Executor executor, Comparator<? super T> c, Long time, List<? extends Callable> list) {
if (list != null && !list.isEmpty()) {
SortedExecutorCompletionService<T> completionService = new SortedExecutorCompletionService<>(executor, time, TimeUnit.MILLISECONDS);
list.stream()
.forEach(completionService::submit);
return completionService.getAllSortedResult();
}
return Collections.EMPTY_LIST;
}
}