JUC并发编程2

线程池

 线程池:七大参数,四中拒绝策略

池化技术: 程序本质 :占用系统资源,要去优化资源的使用==>池化技术

资源的创建和销毁十分浪费系统资源

池化技术就是事先准备一些资源,如果有人要用就来我这里拿,用完还给我,以此提高效率

线程池的好处:

1.降低资源的消耗

2.提高响应速度

3.方便管理

线程池三大方法:

ExecutorService Service = Executors.newSingleThreadExecutor();//单个线程
ExecutorService Service1 = Executors.newFixedThreadPool(5);//创建一个该规定的线程池大小
ExecutorService Service2 = Executors.newCachedThreadPool();//可伸缩的线程池大小

public class ThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();//单个线程
        ExecutorService executorService1 = Executors.newFixedThreadPool(5);//创建一个该规定的线程池大小
        ExecutorService executorService2 = Executors.newCachedThreadPool();//可伸缩的线程池大小

        try {
            //通过线程池去创建线程
            for (int i = 0; i < 10; i++) {
                executorService1.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"创建ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //不使用的话要关闭线程池
            executorService1.shutdown();
        }
    }
}

七大参数:

源码剖析:

    public ThreadPoolExecutor(int corePoolSize,//核心线程池大小
                              int maximumPoolSize,//最大线程池大小
                              long keepAliveTime,//超时了没有人调用就释放
                              TimeUnit unit,//超时单位
                              BlockingQueue<Runnable> workQueue,//阻塞队列
                              ThreadFactory threadFactory,//线程池工厂,一般不用动
                              RejectedExecutionHandler handler) {//拒绝策略
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

小狂神的银行排队案例: 

 阿里巴巴开发手册里面写到我们最好使用new ThreadPoolExecutor去创建线程池,传统的Executors工具类创建不安全,所以我们都要使用new ThreadPoolExecutor去创建线程池

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,
                5,
                3L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

四种拒绝策略: 

        //四种拒绝策略
//        new ThreadPoolExecutor.AbortPolicy(); //不处理任务,抛出异常java.util.concurrent.RejectedExecutionException:
//        new ThreadPoolExecutor.CallerRunsPolicy(); //哪里来的回到哪里去
//        new ThreadPoolExecutor.DiscardOldestPolicy();//尝试跟第一个线程竞争,竞争不上就丢弃掉
//        new ThreadPoolExecutor.DiscardPolicy();//丢弃任务,不抛出异常
        //最大承载 : 最大核心线程池的数量加上阻塞队列的数量

线程最大数量的设计:

调优:

  1. CPU密集型:更加CPU的核心数设定max–Runtime.getRuntime().availableProcessors()

  2. IO密集型:设定的线程数得满足耗时任务的执行,起码要大于它。

四大函数式接口(必须掌握)

新时代的程序员要会的:lambda表达式,链式编程,函数式接口, Stream流式计算

函数式接口:只有一个方法的接口,如:Runable, Callable.......

@FunctionalInterface
public interface Runnable {

    public abstract void run();
}

Function函数式接口源码分析:

/**
 * Function函数式接口
 */
public class demo01 {
    public static void main(String[] args) {
//        Function function = new Function<String,String>() {
//            @Override
//            public String apply(String str) {
//                return str;
//            }
//        };
        //所有的函数式接口都可以用lambda表达式简化
            Function function=(str)->{return str;};
        System.out.println(function.apply("abc"));
    }
}

predicate函数式接口:断定型接口,只有一个输入参数,返回值只能是布尔值!

可以用来判断输入的字符串是否为空,也可以用lambda表达式简化,只要是函数式接口,都可以用lambda表达式简化

消费者型Consumer接口

public class demo03 {
    public static void main(String[] args) {
//        Consumer<String> consumer = new Consumer<String>() {
//
//            @Override
//            public void accept(String str) {
//                System.out.println(str);
//            }
//        };
        Consumer<String> consumer=(str)->{
            System.out.println(str);
        };
        consumer.accept("哈哈哈");
    }
}

Supplier供给型接口 

 

/**
 * 供给型接口,只有返回值,没有输入值,
 */
public class demo04 {
    public static void main(String[] args) {
//        Supplier<String> supplier = new Supplier<String>() {
//            @Override
//            public String get() {
//
//                return "哈哈哈哈哈";
//            }
//        };
        Supplier<String> supplier=()->{
            return "hahahah";
        };
        System.out.println(supplier.get());
    }
}

 Stream流式计算

 大数据:存储+计算

存储: 集合,MySQL;

package Steam;

import java.util.Arrays;
import java.util.List;

/**
 *  要求: 一分钟内完成,只能用一行代码
 * 现在有五个用户!请进行筛选
 * 1.id必须是偶数
 * 2.年龄必须大于23岁
 * 3.用户名转换为大写
 * 4.用户名字母倒着排序
 * 5.只输入一个用户
 */
public class Test {
    public static void main(String[] args) {

        List<User> list = Arrays.asList(
                  new User(1, "a", 21)
                , new User(2, "b", 20)
                , new User(3, "c", 23)
                , new User(4, "d", 28)
                , new User(6, "e", 24)
        );
        //把集合装换为流对象
        list.stream()
                .filter(u->{return u.getId()%2==0;})
                .filter(u->{return u.getAge()>23;})
                .map(u -> {return u.getName().toUpperCase();})
                .sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
                .limit(1)
                .forEach(System.out::println);
    }
}

 ForkJoin

 什么是ForkJoin?

主要是并行执行任务,提高效率! 大数据量

把大任务拆分为小任务

ForkJoin的特点: 工作窃取:比如现在有两个队列,分别有几个小任务在里边,分别有两条线程去跑,如果b线程还没跑完,a线程已经跑完了,a线程就会执行b线程中还没完成的任务

如何使用ForkJoin?

1.创建ForkJoinPool  通过它来执行 他的执行方法

 2.计算任务:forkjoinPool.execute(ForkJoinTask task) 执行

 我们这里写一个计算的任务类继承RecursiveTask类(有返回值的)demo1

/**
 * 求和计算的任务
 * 有三种写法
 * 1.传统for循环
 * 2.forkJoin
 * 3.Stream并行流
 * //如何使用ForkJoin
 * 1.forkjoinPool 通过它来执行
 * 2.计算任务:forkjoinPool.execute(ForkJoinTask task) 执行
 * 3.计算类要继承RecursiveTask<Long>类
 */
public class demo1 extends RecursiveTask<Long> {
    private long start;
    private long end;
    //临界值
    private static long temp=10000L;

    public demo1(Long start, Long end) {
        this.start = start;
        this.end = end;
    }

    //计算的方法
    //这里定义了一个临界值,如果大于这个临界值就会使用我们的ForkJoin方法,如果不大于临界值就使用我们定义的传统方法去计算
    @Override
    protected Long compute() {
        if ((end-start)<=temp){
            Long sum=0L;
            for (Long i = start; i <=end ; i++) {
                sum +=i;
            }
            return sum;
        }else{//forkJoin 递归
         //大事化小,小事化了
            long middle=(start+end) / 2;//中间值
            demo1 task1 = new demo1(start, middle);
            task1.fork();//拆分任务,把任务压入线程队列
            demo1 task2 = new demo1(middle+1, end);
            task2.fork();//拆分任务,把任务压入线程队列
           return task1.join() + task2.join();
        }
    }
}

接下来写一个测试类,有三种方法,第一种是传统方法,第二种是使用了ForkJoin的,第三种是使用了Stream并发流的计算的,也是效率最高的那一种,所有的计算都应该让stream流来做

异步调用Future

 Future的设计初衷:对将来的某个事件的结果进行建模

 CompletableFuture是Future接口的一个实现类,我们用它来发起一个请求,(没有返回值的)

/**
 * 异步调用
 * 执行成功有成功的回调
 * 失败回调
 */
public class demo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //发起一个请求
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"runAsync=>Void");
        });
        System.out.println("11111111");
        completableFuture.get();//获取阻塞执行结果
    }
}

runAsync方法发起一个异步请求, get()方法为阻塞获取执行的结果

执行顺序:这里模拟了延时,

 还有另外一种方法(有返回值的)

        //有返回值的
        //这里的参数需要的是一个供给型参数 没有输入值,只有一个返回值

        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread().getName()+"supplyAsync=>Integer");
            int i =10/0;//这里制造一个错误
            return 1024;
        });

        //成功回调
        //这里需要的参数是一个BiConsumer消费型参数,是Consumer的增强型,他需要的是两个参数
        System.out.println(completableFuture.whenComplete((t, u) -> {
            System.out.println("t" + t); //这是正常的返回结果
            System.out.println("u" + u); //
        }).exceptionally((e) -> {  //失败回调
            System.out.println(e.getMessage());
            return 233; //可以获取错误的返回结果
        }).get());
        
    }

成功回调方法whenComplete(),失败回调方法:exceptionally()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值