美文网首页
Java多线程并发处理任务

Java多线程并发处理任务

作者: GuangHui | 来源:发表于2018-10-16 15:59 被阅读29次

本文主要通过一个获取某个区间内质数的例子来说明如何使用java进行多线程并发处理任务。

1. 需求:

获取某个区间内质数,同时任务在处理完成后,要返回任务执行时间。

分析:

需求中指明要在任务处理完成后,返回执行时间,所以要监听所有任务执行的状态。
高效处理:使用线程池,这里使用接口ExecutorService类;
监听任务状态:使用FutureTask类;

2. 新建一个Math类,并发处理核心类:
package hrt.executor;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;

public class Math {
    private static final int MAX_THREAD_COUNT = 10;

    /**
     * 获取区间中的质数
     * @param start
     * @param end
     * @return
     */
    public static List<Long> getPrimeNumbers(Long start, Long end) {
        Long[] points = getPoints(start, end);

        List<Long> primeNumbers = new ArrayList<Long>();

        List<FutureTask<List<Long>>> futureTaskList = new ArrayList<FutureTask<List<Long>>>();
        ExecutorService excutorService = Executors.newFixedThreadPool(MAX_THREAD_COUNT);
        for (int i = 0; i < points.length - 1; i++) {
            // FutureTask可以看成是一个可以加入线程池的job,用来执行具体的任务
            FutureTask<List<Long>> futureTask = new FutureTask<List<Long>>(
                    new GetPrimeTask(points[i], points[i + 1] - 1));
            futureTaskList.add(futureTask);
            // executorService可以看成是一个线程池,调用submit方法提交Task任务
            excutorService.submit(futureTask);
        }

        for (FutureTask<List<Long>> futureTask : futureTaskList) {
            try {
                // get方法获取job计算得到的结果,该方法只有在Task完成任务后才会有返回.
                List<Long> partPrimeNumbers = futureTask.get();
                primeNumbers.addAll(partPrimeNumbers);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        ThreadPoolExecutor tp = (ThreadPoolExecutor) excutorService;
        System.out.println("池中最大的线程数据" + tp.getMaximumPoolSize() + ",当前池中线程数:" + tp.getPoolSize() + ",完成任务数:"
                + tp.getCompletedTaskCount());

        return primeNumbers;
    }

    /**
     * 判断是否是质数:只能被1和自身整除
     * 
     * @param num
     * @return
     */
    public static boolean isPrimeNumber(Long num) {
        for (Long i = 2L; i <= num / 2; i++) {
            if (num % i == 0) {
                return false;
            }
        }

        return true;
    }

    /**
     * 将数据拆分为多个数据区间
     * @param start
     * @param end
     * @return
     */
    private static Long[] getPoints(Long start, Long end) {
        Long[] points = new Long[MAX_THREAD_COUNT];

        for (int i = 0; i < MAX_THREAD_COUNT - 1; i++) {
            points[i] = start + (end - start) / (MAX_THREAD_COUNT - 1) * i;
        }
        points[MAX_THREAD_COUNT - 1] = end + 1;

        return points;
    }
}

说明:

这个Math类中有两个重要的类,一个是ExecutorService,它可以认为是一个线程池;另外一个是FutureTask, 这个可以认为是可以加入线程池中的一个Job,用来执行具体的任务。

在上面的代码中,我们将每一个FutureTask对象保存起来,然后加入到线程池中并submit提交任务,最后遍历每一个FutureTask对象,通过该对象的get方法来获取这个job计算得到的结果,get方法只有在job完成任务后才会返回。

3. 新建GetPrimeTask类:
package hrt.executor;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
 
public class GetPrimeTask implements Callable<List<Long>> {
 
    private Long start;
    private Long end;
    
    public GetPrimeTask(Long start, Long end) {
        this.start = start;
        this.end = end;
    }
    
    public List<Long> call() throws Exception {
        List<Long> primeNumberList = new ArrayList<Long>();
        
        for (Long i = start; i <= end; i++) {
            //判断是否是质数,是的话插入集合中
            if (Math.isPrimeNumber(i)) {
                primeNumberList.add(i);
            }
        }   
        return primeNumberList;
    }
}

说明:必须要实现Callable接口。

4. 测试程序入口:
package hrt.executor;


import java.sql.Time;
import java.util.Calendar;
import java.util.List;
 
/**
 * 主程序入口
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        System.out.println("start");
        Long startTime = getCurTime();
        
        List<Long> primeNumberList = Math.getPrimeNumbers(200000L, 300000L);
        
        for (Long primeNumber : primeNumberList) {
            System.out.println("" + primeNumber);
        }
        Long endTime = getCurTime();
        
        System.out.println("消耗时间:" + (endTime - startTime) + " ms");
    }
    
    private static Long getCurTime() {
        Calendar c = Calendar.getInstance();
        return c.getTimeInMillis();
    }
}
5. 追加说明:

在Math类中使用的ExecutorService类其实就是一个线程池中线程数固定的线程池,这里固定的线程数有常量 MAX_THREAD_COUNT=10 进行设置。
(1)创建线程池时,初始线程池中线程数为0,当提交的任务数小于线程数时,线程池中的线程数会等于任务数;当提交的任务数大于固定线程数时,多出的任务会处在等待中,当线程池中线程开始有空闲时,才会处理等待中的任务。
(2)对于固定线程数的线程池,当提交的任务处理完成后,线程池中空闲的线程还会一直存在不会中断。

任务执行完毕后,线程还在
6. 参考文章

https://blog.csdn.net/m0_37825799/article/details/79088596

相关文章

  • java面试题(三)

    Java 多线程模块 1、并行和并发有什么区别? 并行:多个处理器或多核处理器同时处理多个任务。 并发:多个任务在...

  • java多线程-线程安全

    Java 中我们往往需要通过多线程进行并发任务处理,在任务处理的过程中如果任务与任务之间存在依赖,那么就需要涉及到...

  • Java多线程并发处理任务

    本文主要通过一个获取某个区间内质数的例子来说明如何使用java进行多线程并发处理任务。 1. 需求: 获取某个区间...

  • Dart 单线程、Isolate

    Dart 单线程模型 众所周知,在Java中使用多线程来处理并发任务,适量并合适地使用多线程,能够极大地提高资源的...

  • 多线程同步与互斥机制

    1、多线程并行和并发的区别 并行:多个处理器或者多核处理器同时执行多个不同的任务。 并发:一个处理器处理多个任务。...

  • JUC指什么?

    JUC是java.util.concurrent并发工具包的简称,是JDK1.5新增处理java多线程并发的工具包

  • Java基础(六)

    多线程 Java多线程并发 1.1 JAVA 并发知识库 1.2 JAVA 线程实现/创建方式 1.2.1 继承 ...

  • 多线程异步任务处理

    @(多线程&&并发) 多线程异步任务处理 欢迎关注作者简书csdn传送门   我们常用ThreadPoolExec...

  • Java多线程之并发协作生产者消费者设计模式JDK1.5.0+升

    上一篇[Java多线程之并发协作生产者消费者设计模式]已经讲述了在Java的多线程中,如何处理并发安全的生产者消费...

  • Python多线程

    多线程基础概念 并行与并发 并行:同时处理多个任务,必须在多核环境下 一段时间内同时处理多个任务,单核也可以并发 ...

网友评论

      本文标题:Java多线程并发处理任务

      本文链接:https://www.haomeiwen.com/subject/ohehzftx.html