关于如何创建自己的Thread工具类

@筱筱斌 2024-01-22 10:16:59

我正在学习多线程方面知识,在完成了代码编写后我突然想将其作为一个工具类来使用,先上代码

如下是我的代码:

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中调用?

...全文
1065 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
T0BSky 05-22
  • 打赏
  • 举报
回复

你正在尝试创建一个通用的多线程工具类 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 方法逻辑。

joedai 01-24
  • 打赏
  • 举报
回复

mark

50,635

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧