项目优化建议

1 bean优化响应式编程

@Data//Lombok自动生成set和get方法,让代码结果简单明了
@Accessors(chain = true)//实现链式调用节省很多时间
public class TestDataVo implements Serializable {
    private String name;
    private String nick;
    private String phone;
    public static void main(String[] args) {
        TestDataVo testDataVo1 = new TestDataVo().setName("afdasf").setNick("afas");
        System.out.println(testDataVo1.name);
        System.out.println(testDataVo1.getName());
        System.out.println(testDataVo1.nick);
        System.out.println(testDataVo1.getNick());
    }
}

2 map装载字符串返回

package com.jeeplus.modules.sms.utils;

import java.util.HashMap;

/**
 * map工具类
 *
 */
public class MapUtils extends HashMap<String, Object> {



    /**
     * 链式调用装载键值对
     * @param key
     * @param value
     * @return
     */
    public  MapUtils put(String key, Object value) {
        super.put(key, value);
        return this;
    }

    public static void main(String[] args) {
        MapUtils utils=new MapUtils();
        MapUtils put = utils.put("1", "2").put("15", "2");
        //iterating over keys only
        for (Object key : put.keySet()) {
            System.out.println("Key = " + key);
        }

    }
}

3 for循环操作数据库(多线程安全处理,缩短操作数据库的时间)

package com.jeeplus.modules.sms.utils.jdk8;

import com.jeeplus.modules.sms.entity.vo.TestDataVo;
import org.apache.commons.lang3.time.DateUtils;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class ThreadUtils {


    public static void main(String[] args) throws Exception {
        // 创建一个固定大小的线程池
        ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
        Date now = new Date();
        Date nextDate = DateUtils.parseDate("2020", "YYYY");
        //CompletableFuture组合式异步编程
        List<CompletableFuture<Void>> futures = IntStream.range(0, 5).mapToObj(j->CompletableFuture.runAsync(()->{
                    List<TestDataVo> list = IntStream.range(0, 20)
                            .mapToObj(i ->new TestDataVo().setName(""+i))
                            .collect(Collectors.toList());
                 //数据库操作逻辑
//               ...
//               ...
                }, service)
        ).collect(Collectors.toList());
        //开始等待所有任务执行完成,线程join是可以加入等待有顺序的,如果其他方法用到了,那当前的先执行
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[]{})).join();
    }



}

4 for循环操作集合等,能用并行流parallelStream()尽量用并行流,时间能节省2/3左右,线程不安全可以通过synchronize,加重入锁ReentrantLock ,collect和reduce收集集合数据让操作变得安全

 

package com.jeeplus.modules.sms.utils.jdk8;

import org.junit.Test;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * Stream操作的三个步骤
 *
 *     创建stream
 *     中间操作(过滤、map)
 *     终止操作
 *     总结就是paralleStream里直接去修改变量是非线程安全的,但是采用collect和reduce操作就是满足线程安全的了。
 *     解决办法
 *         加同步带吗快sycynize
 *         加重入锁ReentrantLock
 *         用collect和reduce收集集合数据
 */
public class Stream {
    private static List<Integer> list1 = new ArrayList<>();
    private static List<Integer> list2 = new ArrayList<>();
    private static List<Integer> list3 = new ArrayList<>();
    private static Lock lock = new ReentrantLock();
   @Test
    public  void main22() {
       List<Integer> numberList = Arrays.asList(1,2,3,4,5,6,7,8,9);

       Set<Integer> collect = numberList.parallelStream().map(Integer::intValue).collect(Collectors.toSet());
       System.out.println(collect.toArray());
       List<Integer> collect1 = numberList.parallelStream().map(Integer::intValue).collect(Collectors.toList());
       System.out.println(collect1.toArray());
       BinaryOperator<Integer> accumulator=new BinaryOperator<Integer>() {
           @Override
           public Integer apply(Integer integer, Integer integer2) {
               return 2;
           }
       };
       Optional<Integer> reduce = numberList.parallelStream().map(Integer::intValue).reduce(accumulator);
       System.out.println(reduce.get());
   }
    /**
     * 线程安全的
     */
    @Test
    public  void main11() {
        Collection<Object> collection = new HashSet<Object>();
        collection.add("af");
        collection.add("afss");
        Collection<Object> synchronizedCollection = Collections.synchronizedCollection(collection);
        //这种遍历方式因为是异步遍历(线程不安全所以要包装collection),会产生一种情况,就是遍历的顺序是无序的,
        // 当然也有相应的好处就是,遍历速度会快,当对生成结果不考虑排序问题而且数据量比较大的时候可以使用.
        if (!CollectionUtils.isEmpty(collection)) {
            collection.parallelStream().forEach(role -> {
                synchronizedCollection.add(role.toString());
                synchronizedCollection.forEach(System.out::println);
            });
        }

    }
    @Test
    public  void main0() {
            IntStream.range(0, 10000).forEach(list1::add);

            IntStream.range(0, 10000).parallel().forEach(list2::add);

            IntStream.range(0, 10000).parallel().forEach(i -> {
                lock.lock();
                try {
                    list3.add(i);
                }finally {
                    lock.unlock();
                }
            });

            System.out.println("串行执行的大小:" + list1.size());
            System.out.println("并行执行的大小:" + list2.size());
            System.out.println("加锁并行执行的大小:" + list3.size());

    }

    public static void main(String[] args) {
//        create();
        // 创建出一个数组
        List<String> strList = Arrays.asList("YangHang", "AnXiaoHei", "LiuPengFei");

        //strList.forEach(System.out::println);
        strList.stream().forEach(System.out::println);
        strList.parallelStream().forEach(System.out::println);
        boolean anXiaoHei = strList.stream().anyMatch((a) -> a.equals("AnXiaoHei"));
        System.out.println(anXiaoHei);
        Optional<String> first = strList.stream().findFirst();
        System.out.println(first.get());
        boolean anXiaoHei1 = strList.stream().anyMatch((a) -> a.equals("AnXiaoHei"));
        System.out.println(anXiaoHei1);
        long count = strList.stream().count();
        System.out.println(count);


    }

    /**
     * 运行结果:
     * For execute time cost 9003 ms
     * Stream execute time cost 9054 ms
     * ParallelStream execute time cost 2007 ms
     * ParallelStream forEachOrdered execute time cost 9013 ms
     * parallelStream().forEach是通过多线程并行的方式来执行我们的代码,而parallelStream(). forEachOrdered也是采用多线程,
     * 但由于加入了顺序执行约束,故程序是采用多线程同步的方式运行的,最终耗时与for、stream两种单线程执行的耗时接近
     */
    @Test
    public  void main3() throws InterruptedException {
        System.out.println("运行结果:");
        List<Integer> numberList = Arrays.asList(1,2,3,4,5,6,7,8,9);
        //for
        Long forBegin = System.currentTimeMillis();
        for(Integer number : numberList){
            //System.out.println(String.format("For The Current Thread's ID is %d and output number %d ",Thread.currentThread().getId(),number));
            Thread.sleep(1000);
        }
        System.out.println(String.format("For execute time cost %d ms",System.currentTimeMillis()-forBegin));
        System.out.println("\r");
        // stream method
        Long streamBegin = System.currentTimeMillis();
        numberList.stream().forEach(number -> {
            //System.out.println(String.format("Stream The Current Thread's ID is %d and output number %d ",Thread.currentThread().getId(),number));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println(String.format("Stream execute time cost %d ms",System.currentTimeMillis()-streamBegin));
        System.out.println("\r");
        // parallelStream method
        Long parallelStreamBegin = System.currentTimeMillis();
        numberList.parallelStream().forEach(number -> {
            //System.out.println(String.format("ParallelStream The Current Thread's ID is %d and output number %d ",Thread.currentThread().getId(),number));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println(String.format("ParallelStream execute time cost %d ms",System.currentTimeMillis()-parallelStreamBegin));
        System.out.println("\r");
        // parallelStream method
        Long parallelStreamForEachOrderBegin = System.currentTimeMillis();
        numberList.parallelStream().forEachOrdered(number -> {
            //System.out.println(String.format("ParallelStream forEachOrdered The Current Thread's ID is %d and output number %d ",Thread.currentThread().getId(),number));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println(String.format("ParallelStream forEachOrdered execute time cost %d ms",System.currentTimeMillis()-parallelStreamForEachOrderBegin));
        System.out.println("\r");
    }

    /**
     * 运行结果:
     * Stream The Current Thread's ID is 1 and output number 1
     * Stream The Current Thread's ID is 1 and output number 2
     * Stream The Current Thread's ID is 1 and output number 3
     * Stream The Current Thread's ID is 1 and output number 4
     * Stream The Current Thread's ID is 1 and output number 5
     * Stream The Current Thread's ID is 1 and output number 6
     * Stream The Current Thread's ID is 1 and output number 7
     * Stream The Current Thread's ID is 1 and output number 8
     * Stream The Current Thread's ID is 1 and output number 9
     *
     * ParallelStream The Current Thread's ID is 1 and output number 6
     * ParallelStream The Current Thread's ID is 1 and output number 5
     * ParallelStream The Current Thread's ID is 12 and output number 3
     * ParallelStream The Current Thread's ID is 1 and output number 2
     * ParallelStream The Current Thread's ID is 15 and output number 7
     * ParallelStream The Current Thread's ID is 13 and output number 8
     * ParallelStream The Current Thread's ID is 1 and output number 1
     * ParallelStream The Current Thread's ID is 12 and output number 4
     * ParallelStream The Current Thread's ID is 15 and output number 9
     *
     * ParallelStream forEach Ordered The Current Thread's ID is 16 and output number 1
     * ParallelStream forEach Ordered The Current Thread's ID is 14 and output number 2
     * ParallelStream forEach Ordered The Current Thread's ID is 14 and output number 3
     * ParallelStream forEach Ordered The Current Thread's ID is 14 and output number 4
     * ParallelStream forEach Ordered The Current Thread's ID is 14 and output number 5
     * ParallelStream forEach Ordered The Current Thread's ID is 14 and output number 6
     * ParallelStream forEach Ordered The Current Thread's ID is 14 and output number 7
     * ParallelStream forEach Ordered The Current Thread's ID is 14 and output number 8
     * ParallelStream forEach Ordered The Current Thread's ID is 14 and output number 9
     */
    @Test
    public  void main2() {
        System.out.println("运行结果:");
        List<Integer> numberList = Arrays.asList(1,2,3,4,5,6,7,8,9);
        // stream method
        numberList.stream().forEach(number -> {
            System.out.println(String.format("Stream The Current Thread's ID is %d and output number %d ",Thread.currentThread().getId(),number));
        });
        System.out.println("\r");
        // parallelStream method
        numberList.parallelStream().forEach(number -> {
            System.out.println(String.format("ParallelStream The Current Thread's ID is %d and output number %d ",Thread.currentThread().getId(),number));
        });
        System.out.println("\r");
        // parallelStream method
        numberList.parallelStream().forEachOrdered(number -> {
            System.out.println(String.format("ParallelStream forEach Ordered The Current Thread's ID is %d and output number %d ",Thread.currentThread().getId(),number));
        });
        System.out.println("\r");
    }


    /**
     *
     运行结果:
     1 2 3 4 5 6 7 8 9
     6 5 3 8 4 2 9 7 1
     1 2 3 4 5 6 7 8 9
     */
    @Test
    public  void main() {
        List<Integer> numberList = Arrays.asList(1,2,3,4,5,6,7,8,9);
        System.out.println("运行结果:");
        // stream method
        numberList.stream().forEach(number -> {
            System.out.print(String.format("%d ",number));
        });
        System.out.println("\r");
        // parallelStream method
        numberList.parallelStream().forEach(number -> {
            System.out.print(String.format("%d ",number));
        });
        System.out.println("\r");
        // parallelStream method
        numberList.parallelStream().forEachOrdered(number -> {
            System.out.print(String.format("%d ",number));
        });
        System.out.println("\r");
    }

    /**
     * stream的创建:
     */
    private static void create() {
        // 1,校验通过Collection 系列集合提供的stream()或者paralleStream()
        List<String> list = new ArrayList<>();
        java.util.stream.Stream<String> stream = list.stream();

        // 2.通过Arrays的静态方法stream()获取数组流
        String[] str = new String[10];
        java.util.stream.Stream<String> stream2 = Arrays.stream(str);
    }

}

 5 CompletableFuture 多线程安全问题处理建议

 

package com.jeeplus.modules.sms.utils.jdk8;

import com.google.common.collect.Lists;
import com.jeeplus.modules.sms.entity.vo.TestDataVo;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.stream.IntStream;

/**
 *
 CompletableFuture API
     runAsync方法不支持返回值。
     supplyAsync可以支持返回值。
     whenComplete 和 whenCompleteAsync 的区别:
     whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
     whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。
     thenApply 方法当一个线程依赖另一个线程时,可以使用 thenApply 方法来把这两个线程串行化。
     handle 是执行任务完成时对结果的处理。
     handle 方法和 thenApply 方法处理方式基本一样。不同的是 handle 是在任务完成后再执行,还可以处理异常的任务。thenApply 只可以执行正常的任务,任务出现异常则不执行 thenApply 方法。
     thenAccept 消费处理结果接收任务的处理结果,并消费处理,无返回结果。跟 thenAccept 方法不一样的是,不关心任务的处理结果。只要上面的任务执行完成,就开始执行 thenAccept 。
     thenCombine 会把 两个 CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 来处理。
     thenAcceptBoth当两个CompletionStage都执行完成后,把结果一块交给thenAcceptBoth来进行消
     applyToEither 方法两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行下一步的转化操作。
     acceptEither 方法两个CompletionStage,谁执行返回的结果快,我就用那个CompletionStage的结果进行下一步的消耗操作。
     runAfterEither 方法两个CompletionStage,任何一个完成了都会执行下一步的操作(Runnable)
     runAfterBoth两个CompletionStage,都完成了计算才会执行下一步的操作(Runnable)
     thenCompose 方法thenCompose 方法允许你对两个 CompletionStage 进行流水线操作,第一个操作完成时,将其结果作为参数传递给第二个操作。
 CountDownLatch 包里面的CountDownLatch其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值
                你可以向CountDownLatch对象设置一个初始的数字作为计数值,任何调用这个对象上的await()方法都会阻塞,直到这个计数器的计数值被其他的线程减为0为止。
 CompletableFuture的allOf方法来实现多实例的同时返回

 总结一下:CompletableFuture多线程任务执行线程不安全解决方案,保持数据原子性
      1 操作的数据用collect/reduce收集
      2  使用CopyOnWriteArrayList(合适读多写少的情况)替换ArrayList
      3  Collections.synchronizedList设置为线程安全类(这里测试比CopyOnWriteArrayList快)
      4  使用join方法再添加到ArrayList
      5  CountDownLatch原子计数器(和4类似)

 */
public class CompletableFutureTest {
    private Logger logger = LoggerFactory.getLogger(getClass());
    // 创建一个固定大小的线程池
    ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
    @Test
    public  void test() {

        //异步调用阿里短信接口发送短信
     CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("发送短信成功1:{}\",\"send sms-------------\"");
                } catch (Exception e) {
                    System.out.println("发送短信失败1:{}\",\"send sms-------------\"");

                }
            }
        },service);

        CompletableFuture.runAsync(() -> {
            try {
                System.out.println("发送短信成功2:{}\",\"send sms-------------\"");
            } catch (Exception e) {
                System.out.println("发送短信失败2:{}\",\"send sms-------------\"");
            }

        });
    }
    private static final int SIZE = 1000000;


    public static void main(String[] args) {
        testCompletableFuture();
        testCompletableFuture2();
        testCompletableFuture3();
    }

    /**
     * 非线程安全,有时出现数组下标越界问题
     */
    public static void testCompletableFuture() {
        System.out.println("----start----" + LocalDateTime.now());
        //由于方法后面的add操作,这里的变量相当于全局变量,造成了线程安全问题出现
        List<Integer> list = new ArrayList<>();
        List<CompletableFuture<Void>> futureList = new ArrayList<>();
        IntStream.range(0, SIZE).forEach(i -> {
            //设置随机返回数字
            CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
                Random random = new Random();
                return random.nextInt(Integer.MAX_VALUE);
            }).thenAccept(list::add);       //添加到list,出现线程安全问题
            futureList.add(future);
        });
        //主线程阻塞等待所有异步线程完成任务
        futureList.forEach(CompletableFuture::join);
        System.out.println("testCompletableFuture - size :" + list.size());
        System.out.println("----end----" + LocalDateTime.now());
        System.out.println();
    }

    /**
     * 线程安全
     * 方法一:使用CopyOnWriteArrayList(合适读多写少的情况)替换ArrayList
     * 方法二:Collections.synchronizedList设置为线程安全类(这里测试比CopyOnWriteArrayList快)
     */
    public static void testCompletableFuture2() {
        System.out.println("----start----" + LocalDateTime.now());
        List<Integer> list = Collections.synchronizedList(new ArrayList<>());
//        List<Integer> list = new CopyOnWriteArrayList<>();
        List<CompletableFuture<Void>> futureList = new ArrayList<>();
        IntStream.range(0, SIZE).forEach(i -> {
            //设置随机返回数字
            CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
                Random random = new Random();
                return random.nextInt(Integer.MAX_VALUE);
            }).thenAccept(list::add);       //添加到list,不会出现线程安全问题
            futureList.add(future);
        });
        //主线程阻塞等待所有异步线程完成任务
        futureList.forEach(CompletableFuture::join);
        System.out.println("testCompletableFuture2 - size : " + list.size());
        System.out.println("----end----" + LocalDateTime.now());
        System.out.println();
    }


    /**
     * 线程安全
     * 使用join方法再添加到ArrayList
     */
    public static void testCompletableFuture3() {
        System.out.println("----start----" + LocalDateTime.now());
        List<Integer> list = new ArrayList<>();
        List<CompletableFuture<Integer>> futureList = new ArrayList<>();
        IntStream.range(0, SIZE).forEach(i -> {
            //设置随机返回数字
            CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
                Random random = new Random();
                return random.nextInt(Integer.MAX_VALUE);
            });
            futureList.add(future);
        });
        //主线程阻塞等待所有异步线程完成任务,并在join返回结果再添加到ArrayList,就不会出现线程安全问题
        futureList.forEach(future-> list.add(future.join()));
        System.out.println("testCompletableFuture3 - size : " + list.size());
        System.out.println("----end----" + LocalDateTime.now());
    }
    @Test
    public  void  hello () throws InterruptedException, ExecutionException {
        List<TestDataVo> list = Lists.<TestDataVo>newArrayList();

        CountDownLatch countDownLatch = new CountDownLatch(2);


        CompletableFuture<TestDataVo> userFuture1 = CompletableFuture.supplyAsync(() -> {
            try {

                return new TestDataVo().setName("ss");

            } catch (Exception e) {
                logger.error("落库失败:{}", e.getMessage());
            } finally {
                countDownLatch.countDown();
            }
            return null;

        },service);

        CompletableFuture<TestDataVo> userFuture2 = CompletableFuture.supplyAsync(() -> {
            try {

                return new TestDataVo().setName("asffas");

            } catch (Exception e) {
                logger.error("落库失败:{}", e.getMessage());
            } finally {
                countDownLatch.countDown();
            }
            return null;

        },service);

        countDownLatch.await();
        list.add(userFuture1.get());
        list.add(userFuture2.get());

        countDownLatch.await();

     list.parallelStream().forEach(System.out::println);
    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BACKWASH2038

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值