Java线程池处理list任务简单例子

需求:前台传递过来一个list,把list中的数据保存到数据库或者同步给远程接口,通过多线程,提高效率

一、先自定义定义线程池,不要用JDK提供的线程池

各种线程池的特点如下:

(1)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
(2)newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
(3)newCachedThreadPool将创建一个可缓存的线程池,当请求增加时,可以添加新的线程,线程池的规模不存在任何限制,线程数的理论值最大可以到Integer.MAX_VALUE
(4)newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

在实际开发中,我们是怎么使用的?(重点)

实际开发中,线程资源必须通过线程池提供,不允许在应用中自行显式创建线程

使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。
如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题

实际开发中,线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式

FixedThreadPool 和 SingleThreadPool,允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
CachedThreadPool 和 ScheduledThreadPool,允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM

所以,综上所述,我们都会采用底层的方式来创建线程池,大家自己查阅各种线程池的源代码就可以看到他们都是采用了同一个类来创建。

//起的线程数
    private static final Integer THREAD_NUM = 5;
    ThreadPoolExecutor pool = new ThreadPoolExecutor(THREAD_NUM, THREAD_NUM * 2, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100));

二、创建任务类,用来处理任务

需要把所有任务(list)传递进来,并且根据情况切分该list,这样每个线程用来完成一部分任务,比如一共20个数据,共有5个线程,每个线程处理4个数据

public class HandleCallable  implements Callable<Integer> {
    private List<String> data;//总的任务
    private int start;
    private int end;

    public HandleCallable(List<String> data, int start, int end) {
        this.data = data;
        this.start = start;
        this.end = end;
    }

    @Override
    public Integer call() throws Exception {
        List<String> subList = data.subList(start, end);
        for (int i = 0; i < subList.size(); i++) {
            System.out.println(Thread.currentThread().getName()+"处理:"+subList.get(i));
        }
        System.out.println(Thread.currentThread().getName()+"处理了"+subList.size()+"条!");
        return 1;//可以根据实际运行结果返回,演示程序设置为1
    }
}

三、创建方法,调用线程池进行处理

    @GetMapping("/deal")
    public void deal() throws ExecutionException, InterruptedException {
        //生产20个任务 模拟前台传递过来的list
        List<String> list = new ArrayList();
        for (int i = 0; i < 20; i++) {
            list.add("任务:" + i);
        }
        //调用线程池处理方法
        handleListCall(list, 5);
    }

    public void handleListCall(List<String> data, int threadNum) throws ExecutionException,         
        InterruptedException {
        List<Integer> futureList = new ArrayList<>();
        int length = data.size();
        int tl = length % threadNum == 0 ? length / threadNum : (length
                / threadNum + 1);
        for (int i = 0; i < threadNum; i++) {
            int end = (i + 1) * tl;
            HandleCallable callable = new HandleCallable(data, i * tl, end > length ?     
            length : end);
            FutureTask<Integer> futureTask = new FutureTask(callable);
            pool.submit(futureTask);
            futureList.add(futureTask.get());//把返回值放到list中,可以方便根据实际结果进行后续 处理逻辑
        }
    }

处理结果:

pool-2-thread-1处理:任务:0
pool-2-thread-1处理:任务:1
pool-2-thread-1处理:任务:2
pool-2-thread-1处理:任务:3
pool-2-thread-1处理了4条!
pool-2-thread-2处理:任务:4
pool-2-thread-2处理:任务:5
pool-2-thread-2处理:任务:6
pool-2-thread-2处理:任务:7
pool-2-thread-2处理了4条!
pool-2-thread-3处理:任务:8
pool-2-thread-3处理:任务:9
pool-2-thread-3处理:任务:10
pool-2-thread-3处理:任务:11
pool-2-thread-3处理了4条!
pool-2-thread-4处理:任务:12
pool-2-thread-4处理:任务:13
pool-2-thread-4处理:任务:14
pool-2-thread-4处理:任务:15
pool-2-thread-4处理了4条!
pool-2-thread-5处理:任务:16
pool-2-thread-5处理:任务:17
pool-2-thread-5处理:任务:18
pool-2-thread-5处理:任务:19
pool-2-thread-5处理了4条!

可以再优化下,给线程起个跟业务相关的名字,方便排查问题

创建线程池的正确姿势,请给它指定一个有意义的名字 - 知乎

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
, 512, 7, 7] 0 Conv2d-116 [-1, 512, 7, 7] 2,359,296 BatchNorm2d-117 [-1, 512, 7,下面是一个简单Java实现线程池的示例代码: ```java import java.util.LinkedList; import java.util 7] 1,024 ReLU-118 [-1, 512, 7, 7] 0 Conv2d-119 [-1, 2048, 7, 7] 1,048,576.List; public class ThreadPool { private final int nThreads; private final List<Worker> workers; private final List<Runnable> BatchNorm2d-120 [-1, 2048, 7, 7] 4,096 taskQueue; public ThreadPool(int nThreads) { this.nThreads = nThreads; this.workers = new LinkedList<>(); this ReLU-121 [-1, 2048, 7, 7] 0 Bottleneck-122 [-.taskQueue = new LinkedList<>(); for (int i = 0; i < nThreads; i++) { Worker worker = new Worker1, 2048, 7, 7] 0 Linear-123 [-1, 1000] (); workers.add(worker); worker.start(); } } public void execute(Runnable task) { synchronized (taskQueue 2,049,000 ================================================================ Total params: 25,557,032 Trainable params: 25,557,) { taskQueue.add(task); taskQueue.notify(); } } private class Worker extends Thread { public void run032 Non-trainable params: 0 ---------------------------------------------------------------- Input size (MB): 0.57 Forward/backward pass size (MB): 342.76 Params size (MB): 97.47 Estimated Total Size (MB): 440.80 () { while (true) { Runnable task = null; synchronized (taskQueue) { while (taskQueue.isEmpty()) { try { taskQueue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } task =---------------------------------------------------------------- ``` 其中 `Total params` 表示网络参数的总数量,本例中为 25,557,032;`Estimated Total Size` 表示模型的总大小,本例中为 440.80 MB;`Forward/backward pass size taskQueue.remove(0); } try { task.run(); } catch (RuntimeException e) { e.printStackTrace(); ` 表示前向和反向传播时需要的内存大小,本例中为 342.76 MB;`Params } } } } } ``` 在这个例子中,我们使用了一个 List 来存储线程池中 size` 表示模型参数的大小,本例中为 97.47 MB。FLOPs 可以通过 `torchprofile的所有工作线程。每个工作线程是一个 Worker 对象,它是一个内部类,继承了` 库来计算,具体实现略有复杂,这里不再赘述。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值