并行化-你的高并发大杀器_并行化 技术

private static final long KEEP_ALIVE_TIME = 5L;
private final static int QUEUE_SIZE = 1600;

protected final static ExecutorService THREAD_POOL = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE,
        KEEP_ALIVE_TIME, TimeUnit.SECONDS, new LinkedBlockingQueue<>(QUEUE_SIZE));
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
    OrderInfo orderInfo = new OrderInfo();
    //CompletableFuture 的List
    List<CompletableFuture> futures = new ArrayList<>();
    futures.add(CompletableFuture.runAsync(() -> {
        System.out.println("当前任务Customer,线程名字为:" + Thread.currentThread().getName());
        orderInfo.setCustomerInfo(new CustomerInfo());
    }, THREAD_POOL));
    futures.add(CompletableFuture.runAsync(() -> {
        System.out.println("当前任务Discount,线程名字为:" + Thread.currentThread().getName());
        orderInfo.setDiscountInfo(new DiscountInfo());
    }, THREAD_POOL));
    futures.add( CompletableFuture.runAsync(() -> {
        System.out.println("当前任务Food,线程名字为:" + Thread.currentThread().getName());
        orderInfo.setFoodListInfo(new FoodListInfo());
    }, THREAD_POOL));
    futures.add(CompletableFuture.runAsync(() -> {
        System.out.println("当前任务Other,线程名字为:" + Thread.currentThread().getName());
        orderInfo.setOtherInfo(new OtherInfo());
    }, THREAD_POOL));
    CompletableFuture allDoneFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
    allDoneFuture.get(10, TimeUnit.SECONDS);
    System.out.println(orderInfo);
}

}


可以看见我们使用CompletableFuture能很快的完成的需求,当然这还不够。


## **3.3 Fork/Join**


我们上面用CompletableFuture完成了我们对多组任务并行执行,但是其依然是依赖我们的线程池,在我们的线程池中使用的是阻塞队列,也就是当我们某个线程执行完任务的时候需要通过这个阻塞队列进行,那么肯定会发生竞争,所以在JDK1.7中提供了ForkJoinTask和ForkJoinPool。


ForkJoinPool中每个线程都有自己的工作队列,并且采用Work-Steal算法防止线程饥饿。 Worker线程用LIFO的方法取出任务,但是会用FIFO的方法去偷取别人队列的任务,这样就减少了锁的冲突。


网上这个框架的例子很多,我们看看如何使用代码其完成我们上面的下订单需求:



public class OrderTask extends RecursiveTask {
@Override
protected OrderInfo compute() {
System.out.println(“执行”+ this.getClass().getSimpleName() + “线程名字为:” + Thread.currentThread().getName());
// 定义其他五种并行TasK
CustomerTask customerTask = new CustomerTask();
TenantTask tenantTask = new TenantTask();
DiscountTask discountTask = new DiscountTask();
FoodTask foodTask = new FoodTask();
OtherTask otherTask = new OtherTask();
invokeAll(customerTask, tenantTask, discountTask, foodTask, otherTask);
OrderInfo orderInfo = new OrderInfo(customerTask.join(), tenantTask.join(), discountTask.join(), foodTask.join(), otherTask.join());
return orderInfo;
}
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool(Runtime.getRuntime().availableProcessors() -1 );
System.out.println(forkJoinPool.invoke(new OrderTask()));
}
}
class CustomerTask extends RecursiveTask{

@Override
protected CustomerInfo compute() {
    System.out.println("执行"+ this.getClass().getSimpleName() + "线程名字为:" + Thread.currentThread().getName());
    return new CustomerInfo();
}

}
class TenantTask extends RecursiveTask{

@Override
protected TenantInfo compute() {
    System.out.println("执行"+ this.getClass().getSimpleName() + "线程名字为:" + Thread.currentThread().getName());
    return new TenantInfo();
}

}
class DiscountTask extends RecursiveTask{

@Override
protected DiscountInfo compute() {
    System.out.println("执行"+ this.getClass().getSimpleName() + "线程名字为:" + Thread.currentThread().getName());
    return new DiscountInfo();
}

}
class FoodTask extends RecursiveTask{

@Override
protected FoodListInfo compute() {
    System.out.println("执行"+ this.getClass().getSimpleName() + "线程名字为:" + Thread.currentThread().getName());
    return new FoodListInfo();
}

}
class OtherTask extends RecursiveTask{

@Override
protected OtherInfo compute() {
    System.out.println("执行"+ this.getClass().getSimpleName() + "线程名字为:" + Thread.currentThread().getName());
    return new OtherInfo();
}

}


我们定义一个OrderTask并且定义五个获取信息的任务,在compute中分别fork执行这五个任务,最后在将这五个任务的结果通过Join获得,最后完成我们的并行化的需求。


### **3.4 parallelStream**


在jdk1.8中提供了并行流的API,当我们使用集合的时候能很好的进行并行处理,下面举了一个简单的例子从1加到100:



public class ParallelStream {
public static void main(String[] args) {
ArrayList list = new ArrayList();
for (int i = 1; i <= 100; i++) {
list.add(i);
}
LongAdder sum = new LongAdder();
list.parallelStream().forEach(integer -> {
// System.out.println(“当前线程” + Thread.currentThread().getName());
sum.add(integer);
});
System.out.println(sum);
}
}


parallelStream中底层使用的那一套也是Fork/Join的那一套,默认的并发程度是可用CPU数-1。


### **3.5 分片**


可以想象有这么一个需求,每天定时对id在某个范围之间的用户发券,比如这个范围之间的用户有几百万,如果给一台机器发的话,可能全部发完需要很久的时间,所以分布式调度框架比如:elastic-job都提供了分片的功能,比如你用50台机器,那么id%50=0的在第0台机器上,=1的在第1台机器上发券,那么我们的执行时间其实就分摊到了不同的机器上了。


## **4.并行化注意事项**


* 线程安全:在parallelStream中我们列举的代码中使用的是LongAdder,并没有直接使用我们的Integer和Long,这个是因为在多线程环境下Integer和Long线程不安全。所以线程安全我们需要特别注意。
* 合理参数配置:可以看见我们需要配置的参数比较多,比如我们的线程池的大小,等待队列大小,并行度大小以及我们的等待超时时间等等,我们都需要根据自己的业务不断的调优防止出现队列不够用或者超时时间不合理等等。


## **5.最后**


本文介绍了什么是并行化,并行化的各种历史,在Java中如何实现并行化,以及并行化的注意事项。希望大家对并行化有个比较全面的认识。最后给大家提个两个小问题:


1. 在我们并行化当中有某个任务如果某个任务出现了异常应该怎么办?
2. 在我们并行化当中有某个任务的信息并不是强依赖,也就是如果出现了问题这部分信息我们也可以不需要,当并行化的时候,这种任务出现了异常应该怎么办?  
 己的业务不断的调优防止出现队列不够用或者超时时间不合理等等。


## **5.最后**


本文介绍了什么是并行化,并行化的各种历史,在Java中如何实现并行化,以及并行化的注意事项。希望大家对并行化有个比较全面的认识。最后给大家提个两个小问题:


1. 在我们并行化当中有某个任务如果某个任务出现了异常应该怎么办?
2. 在我们并行化当中有某个任务的信息并不是强依赖,也就是如果出现了问题这部分信息我们也可以不需要,当并行化的时候,这种任务出现了异常应该怎么办?




![img](https://img-blog.csdnimg.cn/img_convert/3e9d67553ec43827040e23957cf97249.png)
![img](https://img-blog.csdnimg.cn/img_convert/309d9e2867a5b55011c57a5076f0dae6.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

真正的技术提升。**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值