多线程之分段处理List集合

多线程 专栏收录该内容
0 篇文章 0 订阅

一、基础

1.1 Callable接口

一般线程的创建有三种方式,直接继承Thread实现Runnable接口实现Callable接口其中最差当属直接继承Thread,调用new Thread()创建的线程缺乏管理,可以随意创建、相互竞争。而后两种可以使用Executor框架的线程池来管理线程,执行任务,可以重用存在的线程,减少对象创建、消亡的开销,提供定时执行、定期执行、单线程、并发数控制等功能。

1.2 Executor框架

Executor框架的主要成员:

  • ThreadPoolExecutor
  • ScheduledThreadPoolExecutor
  • Future接口
  • Runnable接口
  • Callable接口
  • Executors

Java通过Executors提供几种线程池,以下为部分方法: 

1.public static ExecutorService newFixedThreadPool(int nThreads) 创建固定数目线程的线程池。

        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            Runnable syncRunnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            };
            executorService.execute(syncRunnable);
        }

 总共只会创建5个线程,当五个线程都处于活动状态时,再次提交的任务都会加入等待队列,直到某活跃线程运行结束

 

2.public static ExecutorService newCachedThreadPool() 创建一个可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。

   ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            Runnable syncRunnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            };
            executorService.execute(syncRunnable);
        }

 

3.public static ExecutorService newSingleThreadExecutor() 创建一个单线程化的Executor。

   ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            Runnable syncRunnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            };
            executorService.execute(syncRunnable);
        }

只会创建一个线程,当上一个执行完之后才会执行第二个。唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行 

1.3 Future

Future就是对于具体的Runnable或者Callable任务的执行结果,进行取消、查询是否完成、获取结果

源码如下:

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}
  • cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务 ;
  • isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true;
  • isDone方法表示任务是否已经完成,若任务完成,则返回true;
  • get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
  • get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。

1.4 FutureTask

FutureTask类实现了RunnableFuture接口,而RunnableFuture继承了Runnable接口和Future接口,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

1.5 Callable+Future案例

public class Test {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        Future<Integer> result = executor.submit(task);
        executor.shutdown();
         
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
         
        System.out.println("主线程:"+Thread.currentThread().getName() + " 正在执行任务!");
         
        try {
            System.out.println("task运行结果"+result.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
         
        System.out.println("所有任务执行完毕");
    }
}
class Task implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("子线程:" + Thread.currentThread().getName()+" 正在工作!");
        Thread.sleep(3000);
        int sum = 0;
        for(int i=0;i<100;i++)
            sum += i;
        return sum;
    }
}

1.6 Callable+FutureTask案例

public class Test {
    public static void main(String[] args) {
        //第一种方式
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
        executor.submit(futureTask);
        executor.shutdown();
        
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        System.out.println("主线程:"+Thread.currentThread().getName() + " 正在执行任务!");

        try {
            System.out.println("task运行结果"+futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("所有任务执行完毕");
    }
}
class Task implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("子线程:" + Thread.currentThread().getName()+" 正在工作!");
        Thread.sleep(3000);
        int sum = 0;
        for(int i=0;i<100;i++)
            sum += i;
        return sum;
    }
}

二、分段List集合处理

    public void dealListWithMutiThread(){
        List<Object> list = new ArrayList<Object>(10000);
        list.add("mark");
        list.add("mario");
        list.add("mk");
        list.add("marks");
        list.add("marios");
        list.add("mks");

        // 每n条数据开启一条线程
        int threadSize = 6;
        // 总数据条数
        int dataSize = list.size();
        // 线程数
        int threadNum = dataSize / threadSize + 1;
        // 定义标记 dataSize / threadSize整除时(threadNum多了一次)
        boolean special = dataSize % threadSize == 0;

        ExecutorService ex = Executors.newFixedThreadPool(threadNum);
        List<Future<List<Object>>> futures = new ArrayList<>(threadNum);
        //分配
        for (int i = 0; i < threadNum; i++) {
            if (i == threadNum - 1) {
                if (special) {
                    break;
                }
                futures.add(ex.submit(new Task(list,threadSize * i,dataSize)));
            } else {
                futures.add(ex.submit(new Task(list,threadSize * i,threadSize * (i + 1))));
            }
        }
        try {
            //处理
            List<Object>  result = new ArrayList<>();
            for(Future<List<Object>> future : futures){
                //如果任务没有完成则忙等待
                while (!future.isDone());
                System.out.println(future.get());
                //合并操作
                result.addAll(future.get());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池,不再接收新的任务
            ex.shutdown();
        }

    }

    private class Task implements Callable<List<Object>> {

        private List<Object> list;
        private int start;
        private int end;

        public Task(List<Object> list,int start,int end){
            this.list = list;
            this.start = start;
            this.end = end;
        }

        @Override
        public List<Object> call() throws Exception {
            Object obj = null;
            List<Object> retList = new ArrayList<Object>();
            for(int i=start;i<end;i++){
                obj = list.get(i);
                //处理逻辑
                retList.add(obj);
                System.out.println("当前线程:"+ Thread.currentThread().getName());
            }
            //返回处理结果
            return retList;
        }
    }

 

  • 0
    点赞
  • 0
    评论
  • 10
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值