JAVA根本之七-Collection和它的并行和流处理

打印 上一主题 下一主题

主题 905|帖子 905|积分 2715

Collection 翻下词典,有很多含义:
收集;聚集;(常指同类的)收藏品;募捐,募集;作品集;聚积;取走;一群人;拿走;(常为季节性推出的)系列时装(或家用品);一批物品
选择“聚集”作为翻译名,我以为可行,除非我们现在重新创造一个汉语词组。
 
对于CRUD和非CRUD,聚集都是一个无比重要的东西,因为计算机的本质是对信息的处理。
信息一般不是单个,是一堆,一堆堆,一块块,一个个....
 
网上关于聚集的资料无比多,所以本文主要是做一个简要的介绍,并添加一些注意事项和个人感悟。
 
一、简介

不外Collection的子孙过于多,用现有词汇命名这些子孙并不容易,有待创建新的词汇。
常用知名子孙有:
List  --  列表,javaDoc的释义是:有序聚集。
   --ArrayList   动态大小列表 ,这是crud中最常用的范例 。不包管顺序
   --LinkedList  双链列表,可以固定成员顺序。本身实现了Deque的接口,可用于辅助实现FiLo的算法
Set  - 无重复聚集,允许有一个null成员
  ---TreeSet   有序聚集
  -- HastSet  哈希聚集  ,主要是操纵的性能好一些
    -- LinkedHashSet  双向链哈希聚集,保持了插入顺序,又具有对应的性能
Queue -队列
   --Deque  双端操纵队列。它有一个著名的实现  LinkedList
Buffer --缓冲
  不外这个主要是阿帕奇的实现org.apache.commons.collections.Buffer,算不得java的根本范例
 
如果是初级程序员,大概以CRUD为主的,那么只要学些掌握ArrayList就差不多了,因为现在的大部分的ORM大概JDBC的上级实现都适用ArrayList来存储数据集。
 
二、聚集的基本方法

仅仅介绍Collection的接口方法,为了便于理解,以LinkedList为例子。
这些方法都极其简单,也没有什么特别好解释的,直接上例子吧!
  1. package study.base.types.collection.list;
  2. import java.util.*;
  3. import java.util.concurrent.CountDownLatch;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.stream.Collectors;
  7. /**
  8. * 演示Collection接口的基本操作和LinkedList的一些典型操作
  9. * @author lto
  10. */
  11. public class TestLinkedList {
  12.     private LinkedList<MoneyJar> list;
  13.     private String[] givers = new String[]{"爸爸","妈妈","哥哥","姐姐","爷爷","奶奶"};
  14.     private Random random = new Random();
  15.     private Map<String,Long> realGivers;
  16.     public TestLinkedList(int size) {
  17.         this.list = new LinkedList<>();
  18.         this.realGivers = new HashMap<>();
  19.         //插入100个MoneyJar,金额和日期都是随机的,giver是随机
  20.         for (int i = 0; i < size; i++) {
  21.             String giver = givers[random.nextInt(givers.length)];
  22.             int amount = random.nextInt(100);
  23.             this.list.add(new MoneyJar(giver, amount, new Date()));
  24.         }
  25.         //按照giver分组统计个数,并赋值给realGivers
  26.         this.list.stream().collect(Collectors.groupingBy(MoneyJar::giver,
  27.                 Collectors.counting())).forEach((k,v)->{
  28.             realGivers.put(k,(long)v);});
  29.         //打印realGivers
  30.         this.realGivers.forEach((k,v)->{System.out.println(String.format("%s共有%d个", k, v));});
  31.     }
  32.     public void count(){
  33.         long start = System.currentTimeMillis();
  34.         final long[] total = {0};
  35.         this.list.spliterator().forEachRemaining(mj-> total[0] += mj.amount());
  36.         System.out.println(String.format("总共%d元",total[0]));
  37.         System.out.println("耗费时间:"+(System.currentTimeMillis()-start));
  38.     }
  39.     public void sortByAmount(){
  40.         this.list.sort((o1, o2) -> o1.amount().compareTo(o2.amount()));
  41.     }
  42.     /**
  43.      * 统计每个giver给的钱,并打印结果
  44.      */
  45.     public void sumByGiver(){
  46.         System.out.println("--------------------****************-----------------------------");
  47.         //根据giver分组统计每个giver给的钱,并返回一个ListMap
  48.         long start = System.currentTimeMillis();
  49.         Map<String, Integer> result= this.list.stream().collect(Collectors.groupingBy(MoneyJar::giver,
  50.                 Collectors.summingInt(MoneyJar::amount)));
  51.         //打印统计结果
  52.         result.forEach((k,v)->{System.out.println(String.format("%s给的钱是%d", k, v));});
  53.         System.out.println("耗费时间:"+(System.currentTimeMillis()-start));
  54.         //采用for循环的方式,分组统计
  55.         System.out.println("采用for循环的方式,分组统计-----------------------------");
  56.         long start1 = System.currentTimeMillis();
  57.         Map<String,List<Integer>> result1= new HashMap<>();
  58.         //初始化result1,把realGivers的每个元素作为key,初始值为0
  59.          this.realGivers.forEach((k,v)->{
  60.             result1.put(k,new ArrayList<>());
  61.         });
  62.         //遍历list,计算每个giver给的钱
  63.         for (MoneyJar moneyJar : list) {
  64.            result1.get(moneyJar.giver()).add(moneyJar.amount());
  65.         }
  66.         //根据result1的成员个数,创建对应的线程,然后在线程中计算每个giver给的钱,并计算总和
  67.         int numThreads=result1.size();
  68.         CountDownLatch latch = new CountDownLatch(numThreads);
  69.         ExecutorService executor = Executors.newFixedThreadPool(numThreads);
  70.         result1.forEach((k,v)->{
  71.             Runnable worker = () -> {
  72.                 try {
  73.                     long sum=0;
  74.                     for (int i : v) {
  75.                         sum+=i;
  76.                     }
  77.                     System.out.println(String.format("%s给的钱是%d", k, sum));
  78.                 } finally {
  79.                     latch.countDown(); // 计数减一
  80.                 }
  81.             };
  82.             // 使用executor提交任务,而不是直接启动Thread
  83.             executor.submit(worker);
  84.         });
  85.         try {
  86.             // 等待所有线程完成
  87.             latch.await();
  88.             System.out.println("All threads have finished.");
  89.         } catch (InterruptedException e) {
  90.             e.printStackTrace();
  91.         }
  92.         // 关闭executor,释放资源
  93.         executor.shutdown();
  94.         System.out.println("耗费时间:"+(System.currentTimeMillis()-start1));
  95.     }
  96.     public void splitToSum(){
  97.         //把钱罐的钱分为n份,分别统计,然后再合并总的金额,并统计耗费时间
  98.         System.out.println("--   采用并行流的方法");
  99.         long start = System.currentTimeMillis();
  100.         Long total=list.parallelStream().mapToLong(MoneyJar::amount).sum();
  101.         System.out.println("耗费时间:"+(System.currentTimeMillis()-start));
  102.         System.out.println("总金额是"+total.toString());
  103.         //采用传统的for循环方式累积
  104.         System.out.println("--   采用传统的for循环的方法");
  105.         start = System.currentTimeMillis();
  106.         long sum=0;
  107.         for (MoneyJar moneyJar : list) {
  108.             sum+=moneyJar.amount();
  109.         }
  110.         System.out.println("总金额是"+sum);
  111.         System.out.println("耗费时间:"+(System.currentTimeMillis()-start));
  112.     }
  113.     /**
  114.      * 把小于等于指定的金额的钱都清理掉
  115.      * @param amount
  116.      */
  117.     public void purgeSmallMoney(int amount){
  118.         this.list.removeIf(moneyJar -> moneyJar.amount()<=amount);
  119.     }
  120.     record MoneyJar(String giver,Integer amount,
  121.                     Date putDay){
  122.     }
  123.     public static void main(String[] args) {
  124.         //当10万个的时候,并行的速度反而是for的3倍左右。
  125.         TestLinkedList test = new TestLinkedList(200);
  126.         test.splitToSum();
  127.         test.sortByAmount();
  128.         System.out.println("-- 排序后 -----");
  129.         for (MoneyJar moneyJar : test.list) {
  130.             System.out.println(moneyJar);
  131.         }
  132.         //测试100万的情况
  133.         TestLinkedList test100 = new TestLinkedList(1000000);
  134.         test100.splitToSum();
  135.         //测试2000万的情况
  136.         TestLinkedList test1000 = new TestLinkedList(20000000);
  137.         test1000.splitToSum();
  138.         //以上三个例子,哈无例外,都是简单的循环胜出。那么parametrizedStream的效率就值得怀疑了。
  139.         //是否因为没有正确设置并行度,还是计算机的环境存在问题
  140.         test1000.sumByGiver();
  141.         test1000.count();
  142.     }
  143. }
复制代码
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

商道如狼道

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表