50,639
社区成员
![](https://csdnimg.cn/release/cmsfe/public/img/topic.427195d5.png)
![](https://csdnimg.cn/release/cmsfe/public/img/me.40a70ab0.png)
![](https://csdnimg.cn/release/cmsfe/public/img/task.87b52881.png)
![](https://csdnimg.cn/release/cmsfe/public/img/share-circle.3e0b7822.png)
我正在学习多线程方面知识,在完成了代码编写后我突然想将其作为一个工具类来使用,先上代码
如下是我的代码:
public class ThreadUtilLink {
public static void main(String[] args) {
long startTime = new Date().getTime();
List<Integer> list = new LinkedList<Integer>();
// 创建数据样本
for (int i = 0; i < 100000; i++) {
list.add(i);
}
List<CallableTest> threadList = new LinkedList<CallableTest>();
// 数据划分 将list分为splitListNum份,并返回对应的List<list>
List<List<Integer>> lists = SplitList.averageAssignByNum(list, 6);
for (List<Integer> integerList : lists) {
CallableTest ct = new CallableTest(integerList);
// 存储线程
threadList.add(ct);
}
// 反转顺序
Collections.reverse(threadList);
List<FutureTask<Integer>> taskList = new LinkedList<FutureTask<Integer>>();
// 遍历线程并执行
for (CallableTest callableTest : threadList) {
FutureTask<Integer> ft = new FutureTask<Integer>(callableTest);
Thread td = new Thread(ft,(threadList.indexOf(callableTest)+1)+"线程");
td.start();
// 回收结果
taskList.add(ft);
}
Collections.reverse(taskList);
for (FutureTask<Integer> integerFutureTask : taskList) {
//获取并输出子线程call()方法的返回值
try {
System.out.println((taskList.indexOf(integerFutureTask)+1)+"线程共处理数据:" + integerFutureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
long stopTime = new Date().getTime();
System.out.println("共耗时 " + (stopTime - startTime)+" ms");
}
}
class CallableTest implements Callable<Integer> {
public CallableTest() {
}
List<Integer> list;
public CallableTest(List<Integer> list) {
this.list = list;
}
//复写call() 方法,call()方法具有返回值
public Integer call() throws Exception {
int i = 0;
for( ; i<list.size(); i++){
// System.out.println(Thread.currentThread().getName() + "的变量值为:" + list.get(i));
}
return list.size();
}
}
这是我突发奇想做的一个多线程的代码,跑起来还不错,当然不排除还有问题,因为我发现每次第一个线程的完成结果打印并不在结尾位置:
1线程共处理数据:1667
...
...
2线程共处理数据:1667
3线程共处理数据:1667
4线程共处理数据:1667
5线程共处理数据:1667
6线程共处理数据:1665
不过我也不太清楚有什么影响,但是感觉不对劲。希望大家如果能看出来为什么的话和我说一声嘿嘿。
先回归正题,因上所以我想把它打成jar包那种形式,然后在每次调用ThreadUtilLink这个类的时候可以搞成如下的形式:
ThreadUtilLink th = new ThreadUtilLink(list,5);
@Override
public Integer call() throws Exception {
int i = 0;
for( ; i<list.size(); i++){
System.out.println(Thread.currentThread().getName() + "的变量值为:" + list.get(i));
}
return list.size();
}
该如何操作嘞,我觉得这样会方便点,但不知道该如何搞,求帮助!
我自己写了一下,代码如下:
public class ThreadUtilLink<E> {
private List<E> list = new LinkedList<E>();
private int num = 5;
public ThreadUtilLink(List<E> list, int num) {
this.list = list;
this.num = num;
}
public static void main(String[] args) {
List<String> list = new LinkedList<String>();
// 创建数据样本
for (int i = 0; i < 10000; i++) {
list.add(String.valueOf(i));
}
// ThreadUtilLink<String> link = new ThreadUtilLink<String>(list,5);
ThreadUtilLink<String> link = new ThreadUtilLink<String>(list, 5);
link.CreateThread();
}
public void CreateThread() {
long startTime = new Date().getTime();
List<CallableTest> threadList = new LinkedList<CallableTest>();
// 数据划分 将list分为splitListNum份,并返回对应的List<list>
List<List<E>> lists = SplitList.averageAssignByNum(this.list, this.num);
for (List<E> integerList : lists) {
CallableTest ct = new CallableTest(integerList);
// 存储线程
threadList.add(ct);
}
// 反转顺序
Collections.reverse(threadList);
List<FutureTask<Integer>> taskList = new LinkedList<FutureTask<Integer>>();
// 遍历线程并执行
for (CallableTest callableTest : threadList) {
FutureTask<Integer> ft = new FutureTask<Integer>(callableTest);
Thread td = new Thread(ft, (threadList.indexOf(callableTest) + 1) + "线程");
td.start();
// 回收结果
taskList.add(ft);
}
Collections.reverse(taskList);
for (FutureTask<Integer> integerFutureTask : taskList) {
//获取并输出子线程call()方法的返回值
try {
System.out.println((taskList.indexOf(integerFutureTask) + 1) + "线程共处理数据:" + integerFutureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
long stopTime = new Date().getTime();
System.out.println("共耗时 " + (stopTime - startTime) + " ms");
}
class CallableTest implements Callable<E> {
List<E> list;
public CallableTest(List<E> list) {
this.list = list;
}
//复写call() 方法,call()方法具有返回值
public E call() throws Exception {
int i = 0;
for (; i < list.size(); i++) {
System.out.println(Thread.currentThread().getName() + "的变量值为:" + list.get(i));
}
return list.size();
}
}
}
不过有几个问题:
1、CallableTest这个类的实现类Callable的泛型与call()方法的返回值必须要相同,如果我想个性化call方法的话这里就成了一个阻碍,因为我无法灵活的设定返回值。这部分该如何解决呢?
2、如何把call()方法做成必须重写的方法呢?通过在call方法外单独写个方法然后在call中调用?
你正在尝试创建一个通用的多线程工具类 ThreadUtilLink,并希望能够灵活地设定 Callable 的返回值,同时强制用户重写 call 方法。以下是一个优化版本的实现,解决了这两个问题:
使 CallableTest 类的泛型与 call 方法的返回值一致:通过在 CallableTest 类中使用泛型。
强制重写 call 方法:通过定义一个抽象类或接口,并在 ThreadUtilLink 类中使用它。
以下是优化后的代码:
import java.util.*;
import java.util.concurrent.*;
public class ThreadUtilLink<E, V> {
private List<E> list = new LinkedList<>();
private int num = 5;
private CallableFactory<E, V> callableFactory;
public ThreadUtilLink(List<E> list, int num, CallableFactory<E, V> callableFactory) {
this.list = list;
this.num = num;
this.callableFactory = callableFactory;
}
public static void main(String[] args) {
List<String> list = new LinkedList<>();
// 创建数据样本
for (int i = 0; i < 10000; i++) {
list.add(String.valueOf(i));
}
ThreadUtilLink<String, Integer> link = new ThreadUtilLink<>(list, 5, integerList -> new CallableTest<>(integerList));
link.createThreads();
}
public void createThreads() {
long startTime = new Date().getTime();
List<Callable<V>> threadList = new LinkedList<>();
// 数据划分 将list分为num份,并返回对应的List<list>
List<List<E>> lists = SplitList.averageAssignByNum(this.list, this.num);
for (List<E> sublist : lists) {
threadList.add(callableFactory.createCallable(sublist));
}
// 反转顺序
Collections.reverse(threadList);
List<FutureTask<V>> taskList = new LinkedList<>();
// 遍历线程并执行
for (Callable<V> callable : threadList) {
FutureTask<V> ft = new FutureTask<>(callable);
Thread td = new Thread(ft, (threadList.indexOf(callable) + 1) + "线程");
td.start();
// 回收结果
taskList.add(ft);
}
Collections.reverse(taskList);
for (FutureTask<V> futureTask : taskList) {
//获取并输出子线程call()方法的返回值
try {
System.out.println((taskList.indexOf(futureTask) + 1) + "线程共处理数据:" + futureTask.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
long stopTime = new Date().getTime();
System.out.println("共耗时 " + (stopTime - startTime) + " ms");
}
// 定义一个工厂接口,用于创建 Callable 实例
interface CallableFactory<E, V> {
Callable<V> createCallable(List<E> list);
}
// 示例的 Callable 实现
static class CallableTest<E> implements Callable<Integer> {
List<E> list;
public CallableTest(List<E> list) {
this.list = list;
}
@Override
public Integer call() {
int i = 0;
for (; i < list.size(); i++) {
System.out.println(Thread.currentThread().getName() + "的变量值为:" + list.get(i));
}
return list.size();
}
}
}
// SplitList 类实现,假设其包含一个静态方法 averageAssignByNum
class SplitList {
public static <T> List<List<T>> averageAssignByNum(List<T> source, int n) {
List<List<T>> result = new ArrayList<>();
int remainder = source.size() % n;
int number = source.size() / n;
int offset = 0; // 偏移量
for (int i = 0; i < n; i++) {
List<T> value;
if (remainder > 0) {
value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
remainder--;
offset++;
} else {
value = source.subList(i * number + offset, (i + 1) * number + offset);
}
result.add(value);
}
return result;
}
}
在这个实现中:
ThreadUtilLink 类现在接受一个 CallableFactory 接口的实现,该接口定义了一个方法 createCallable,用于创建 Callable 实例。
CallableTest 类使用泛型,允许灵活设定 call 方法的返回值类型。
在 main 方法中,通过传递一个 lambda 表达式实现 CallableFactory 接口,创建 CallableTest 实例。
这种方式使得 ThreadUtilLink 类能够灵活地处理不同类型的任务,同时强制用户提供自定义的 call 方法逻辑。
mark