JUC Day03 (阻塞队列、JAVA1.8特性、Stream流式编程、异步回调)

7.Callable(简单)

在这里插入图片描述
1、Callable 能够返回结果
2、能够报异常
3、方法与Runable 和Thread不同

代码:

package Callable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @Description:
 * @Author Bowen
 * @Date 2021/1/14 15:28
 **/
public class DemoCallable {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        new Thread().start();//怎么启动Callable
//        new Thread(new FutureTask<V>()).start();
//        new Thread(new FutureTask<V>(callable)).start();
// 因为想要实现调用callable就要实现runnable ,那么FutureTask就是Runnable的实现类
// 并且FutureTask的构造器方法中能够接收callable参数,所以即可完成调用
        new Thread().start();

        MyThread myThread = new MyThread();
        FutureTask futureTask = new FutureTask(myThread);

        new Thread(futureTask,"A").start();
        new Thread(futureTask,"B").start(); //只打印一次Call(),因为有缓存
        // 获取返回值,【可能会发生阻塞】:建议放在最后一行或者异步通信
        Integer o = (Integer) futureTask.get(); 
        System.out.println(o);
    }
}

class MyThread implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        System.out.println("call()");
        return 1024;
    }
}

细节:
1、有缓存
2、可能会发生阻塞

8、常用的辅助类

8.1 CountDownLatch(重点)(减法计数器)

在这里插入图片描述
代码:

package SecUtils;

import java.util.concurrent.CountDownLatch;

/**
 * @Description:
 * @Author Bowen
 * @Date 2021/1/14 16:37
 **/
public class DemoCountDownLunch {
    public static void main(String[] args) throws InterruptedException {
        // 倒计时 总数为6
        CountDownLatch countDownLatch = new CountDownLatch(6);

        for (int i = 0; i < 6 ; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"go Out");
                countDownLatch.countDown();//计数器 -1  Bowen
            },String.valueOf(i)).start();

        }
        countDownLatch.await();//等计数器归零才继续往下走;
        System.out.println("close Door");
    }
}
/**
结果为:
0go Out
2go Out
4go Out
3go Out
1go Out
5go Out
close Door 
**/

方法:
0:初始化的时候规定初始数
1:countDown() 计数器-1
2:await() 当归零再向下执行

8.2 CyclicBarrier(加法计数器)

在这里插入图片描述
代码:

package SecUtils;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @Description:
 * @Author Bowen
 * @Date 2021/1/14 16:44
 **/
public class DemoCyclicBarrier {
    public static void main(String[] args) {
        //  集齐个数

        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("集齐7个");
        });

        for (int i = 0; i < 7 ; i++) {
//            lamda表达式能够操作到i嘛 实际上是不能的
//            解决方法:将循环中的i赋值给一个final int 变量即可 不写final在1.8jvm中也会默认加上
            int temp = i;
            new Thread(()->{
                try {
                    System.out.println("第"+temp+"个");
                    cyclicBarrier.await();//    await0为共计有7个线程时,完成cyclicBarrier初始化中的lamda方法,并且阻塞
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },i+"").start();
        }
    }
}

/**
结果:
第0个
第2个
第3个
第4个
第6个
第1个
第5个
集齐7个

**/

8.3 Semaphore(信号量,限流)

在这里插入图片描述

代码:

package SecUtils;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * @Description:
 * @Author Bowen
 * @Date 2021/1/15 8:39
 **/
public class DemoSemaphore {
    public static void main(String[] args) {
//        线程数量,限流
        Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i < 6 ; i++) {
            new Thread(()->{
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"进入位置");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName()+"离开位置");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();
                }
            },i+"").start();
        }
    }
}
/**
结果:
 0进入位置
2进入位置
1进入位置
0离开位置
1离开位置
2离开位置
4进入位置
5进入位置
3进入位置
5离开位置
3离开位置
4离开位置
**/

原理:
Semaphore semaphore = new Semaphore(3); 初始化限制数
semaphore.acquire();记录线程数,如果达到上限,等待,等待释放为止
semaphore.release();释放线程数
作用:
多个共享资源互斥的使用!并发限流,控制最大的线程数。

9、读写锁

在这里插入图片描述
代码:

package lock;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 独占锁(写锁)只能一个线程占有
 共享锁(读锁)多个线程可以同时占有
 ReadWriteLock
 读-读    可以共存
 读-写    不能共存
 写-写    不能共存
 **/
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyCache myCache = new MyCache();

//        存,
        for (int i = 0; i < 100; i++) {
            int temp = i;
            new Thread(()->{
                myCache.put(temp+"",temp+":value");
            },i+"").start();
        }

//        读取
        for (int i = 0; i < 100; i++) {
            int temp = i;
            new Thread(()->{
                myCache.get(temp+"");
            },i+"").start();
        }
    }
}

class MyCache{

    private volatile Map<String, Object> map = new HashMap<>();
    //        读写锁,更加细粒度的操作
    ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    //    存、写 写入的时候,只希望同时只有一个线程写入
    public void put(String key, Object value){
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"写入…"+key);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+"写入完成"+key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }

    }

//    取、读 所有人都去读
    public void get(String key){
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"读取…"+key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName()+"读取完成"+key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }

    }
}

阻塞队列

阻塞:

  • 写入:如果队列满了,就必须阻塞
  • 读取:如果队列是空的,必须阻塞,等待生产写入

队列:

  • FIFO (First In Frist Out 模式)先进先出
    在这里插入图片描述
    什么情况下会使用阻塞队列:
    多线程并发、线程池
    在这里插入图片描述

学会使用队列:
添加、移除

四组API

方式抛出异常有返回值,不抛出异常阻塞等待超时等待
添加addoffer()put()重写offer(字段,值,TimeUnit单位)
移除removepoll()take()重写poll(值,TimeUnit单位)
判断队列首elementpeek

1、抛出异常

 public static void test(){
//        初始化时要定义大小
        ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);

        System.out.println(blockingQueue.add("a"));
        System.out.println(blockingQueue.add("b"));
        System.out.println(blockingQueue.add("c"));
//        IllegalStateException:Queue full 抛出异常! 队列满了无法添加
        System.out.println(blockingQueue.add("d"));


        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
//        NoSuchElementException:队列中没有元素的 抛出异常! 队列空了无法删除
        System.out.println(blockingQueue.remove());
    }

2、不会抛出异常

  public static void test02(){
//        初始化时要定义大小
        ArrayBlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(3);

        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
//        与add方法不同,这个错误只会返回false不会报错
        System.out.println(blockingQueue.offer("d"));

        System.out.println(blockingQueue.poll());
//        System.out.println(blockingQueue.remove());
    }

3、阻塞等待

    public static void test03() throws InterruptedException {
//        初始化
        ArrayBlockingQueue<Object> bq = new ArrayBlockingQueue<>(3);

        //等待、阻塞
        bq.put("1");
        bq.put("2");
        bq.put("3");
        //添加进不去之后就会一直阻塞等待
        bq.put("4");
        System.out.println(bq.take());

    }

4、超时不等待

    public static void test04() throws InterruptedException {

        ArrayBlockingQueue<Object> bq = new ArrayBlockingQueue<>(2);

        //超时不等待为重写offer/poll的方法
        bq.offer("a",3, TimeUnit.SECONDS);
        bq.offer("b",4,TimeUnit.SECONDS);
    		//如果添加失败 4秒后就放弃
        bq.offer("b",4,TimeUnit.SECONDS);

        bq.poll(2,TimeUnit.SECONDS);
    }

SychronizedQueue

可以理解为一种特殊的阻塞队列,只能存储一个元素
put后需要take取出来之后才能继续put

11、线程池(重点)

三大方法,7大参数,4种拒绝策略

池化技术

程序运行的本质=》占用系统资源!应对=》优化资源的使用=》池化技术

例如:线程池、连接池、内存池、对象池
池化技术:实现配置准备好,有人用就在这里取,不会反复实例、销毁

线程池的好处:
1、降低资源的消耗
2、提高响应的速度
3、方便管理
线程复用 限制并发数 管理线程

三大方法

//使用线程池创建
public class Demo01 {
    public static void main(String[] args) {
        ExecutorService threadPool01 = Executors.newSingleThreadExecutor();//单个线程
        ExecutorService threadPool02 = Executors.newFixedThreadPool(5);//创造一个固定的线程池大小

        ExecutorService threadPool03 = Executors.newCachedThreadPool();//可伸缩的,根据情况改变大小


        // 线程池用完,在程序结束前需要关闭线程池 Bowen
        try {
            for (int i = 0; i < 10; i++) {
                threadPool03.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"->OK");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool03.shutdown();
        }
//          threadPool01
//        pool-1-thread-1OK
//        pool-1-thread-1OK
//        pool-1-thread-1OK
//        pool-1-thread-1OK
//        pool-1-thread-1OK
//        pool-1-thread-1OK
//        pool-1-thread-1OK
//        pool-1-thread-1OK
//        pool-1-thread-1OK
//        pool-1-thread-1OK

//        threadPool02
//        pool-1-thread-1->OK
//        pool-1-thread-2->OK
//        pool-1-thread-4->OK
//        pool-1-thread-3->OK
//        pool-1-thread-3->OK
//        pool-1-thread-5->OK
//        pool-1-thread-1->OK
//        pool-1-thread-1->OK
//        pool-1-thread-1->OK
//        pool-1-thread-1->OK
        
//        threadPool03
//        pool-2-thread-1->OK
//        pool-2-thread-2->OK
//        pool-2-thread-3->OK
//        pool-2-thread-1->OK
//        pool-2-thread-1->OK
//        pool-2-thread-3->OK
//        pool-2-thread-4->OK
//        pool-2-thread-2->OK
//        pool-2-thread-6->OK
//        pool-2-thread-5->OK

7大参数

// 本质ThreadPollExecutor

int corePoolSize,//核心线程池大小
int maxmumPoolSize // 最大核心线程池大小
long keepAliveTime // 超时了没有人调用会释放的线程数
TimeUnit unit,//超时单位
BlockingQueue<Runable> workQueue//阻塞队列
ThreadFactory threadFacotry //线程工厂,创建线程的,一般不会用
RejectedExecutionHandler handler // 拒绝策略

手动创建线程池

 //最大线程数如何定义配置
 //  1、CPU密集型 几核就 定义为几,可以保证CPU的效率最高 Runtime.getRuntime().avaliableProcessors();
 //  2、IO密集型 判断程序中是否耗IO的线程,取两倍即可
 //      程序中 15个大型任务 io是否占用资源!
        
 ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
                2, //核心线程数2个,阻塞队列没满就一直是这两个线程在跑,阻塞队列满了就创建线程
                5,//最大线程数为5,超过5个线程根据拒绝策略进行拒绝,最多只能创建5个线程
                3,// 3秒超时自动删除核心线程外的线程
                TimeUnit.SECONDS,//超时的时间单位
                new LinkedBlockingDeque<>(4),//阻塞队列4可以最多容纳4个任务等待线程
                Executors.defaultThreadFactory(),//默认线程创建工厂
                new ThreadPoolExecutor.AbortPolicy());//队列满了,还有人进来就会不处理这个人,报异常
                
                //由线程池创建线程方法:
                poolExecutor.execute(()->{
                	
				})

4种拒绝策略


// 1 队列满了,还有任务进来就会不处理这个任务,报异常
new ThreadPoolExecutor.AbortPolicy()//

java.util.concurrent.RejectedExecutionException: Task poll.Demo02$$Lambda$1/990368553@7cca494b rejected from java.util.concurrent.ThreadPoolExecutor@7ba4f24f[Running, pool size = 5, active threads = 5, queued tasks = 4, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at poll.Demo02.main(Demo02.java:23)

// 2 哪里来的请求,由来源方处理,例如main的任务,就由main自己完成
 new ThreadPoolExecutor.CallerRunsPolicy());
 
main->OK
main->OK
pool-1-thread-4->OK
pool-1-thread-4->OK
pool-1-thread-4->OK

//3 丢弃任务,不会抛出异常

new ThreadPoolExecutor.DiscardPolicy());//丢弃任务,不会抛出异常

// 4 丢弃阻塞队列中的任务,不会抛出异常

new ThreadPoolExecutor.DiscardOldestPolicy());

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

新时代程序员,需要掌握1.8

  • lamda表达式
  • 链式编程
  • 函数式接口
  • Stream流式计算

函数式接口: Function 【输入一个值,处理后返回一个结果值】

 Function function = str-> str;

        System.out.println(function.apply("xxx"));

断定型接口: Predicate 【输入一个值,根据方法返回boolean类型】

   Predicate<String> predicate = str ->{return str.isEmpty();};

        System.out.println(predicate.test("str"));

消费型接口: Consumer 【只有参数,没有return】

Consumer consume = str -> System.out.println(str);

供给型接口: Supplier【只有返回值,没有参数】

Supplier supplier = () -> {return 1024;};

Stream流式计算

大数据:存储+计算
存储:MySQL 本质就是存储东西的;
计算都是应该交给流来操作的
在这里插入图片描述

package Stream;

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

/**
 * 流式计算
 **/
public class Demo01 {
    public static void main(String[] args) {
        User u1 =new User(1,"a",21);
        User u2 =new User(2,"b",22);
        User u3 =new User(3,"c",23);
        User u4 =new User(4,"d",24);
        User u5 =new User(6,"e",26);
        List<User> list = Arrays.asList(u1,u2,u3,u4,u5);

        //  链式编程
        list.stream()
                .filter(u->{ return u.getId()%2==0 ;})
                .filter(u->{return u.getAge()>23;})
                .map(u->{return u.getName().toUpperCase();})
                .sorted((uu2,uu1)->{return uu2.compareTo(uu1);})
                .forEach(System.out::println);

    }
}

class User{

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public User() {
    }

    public User(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    private Integer id;

    private String name;

    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

Forkjoin

什么是Forkjoin

Forkjoin是1.7开始的,并行执行任务,提高效率!
大数据:Map Reduce(把大任务拆分为小任务再把小任务结果 汇总 return)

特点: 工作窃取
不让线程等待:例如AB两个线程,B先执行完任务,会把A未执行的任务偷走执行,顺序为双端队列的另一边
在这里插入图片描述

在这里插入图片描述
Demo类 需要继承RecursiveTask并重写compute方法

package Forkjoin;

import java.util.concurrent.RecursiveTask;

/**
 通过ForkjoinPool 通过它来执行
 forkjoinPool.execute(ForkjoinTask<?> task);
 forkjoinTask
 **/
public class Demo01 extends RecursiveTask<Long> {

        private Long start;
        private Long end;

        private Long temp = 10000L;

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


    @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;//中间值
            Demo01 task1 = new Demo01(start, middle);
            task1.fork();
            Demo01 task2 = new Demo01(middle, end);
            task2.fork();
            return task1.join() + task2.join();
        }
    }
}

测试类

package Forkjoin;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;

/**

 **/
public class test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        test1();
    }

    // 1 Bowen
    public static void test1(){
        long sum = 0L;
        long startTime = System.currentTimeMillis();
        for (long i = 0; i <= 10_0000_0000; i++) {
            sum += i;
        }
        long endTime = System.currentTimeMillis();
        System.out.println(sum + ":" + (endTime-startTime));
    }

    public static void test2() throws ExecutionException, InterruptedException {
        long startTime =System.currentTimeMillis();

        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask task = new Demo01(0L, 10_0000_0000L);
        ForkJoinTask<Long> submit = forkJoinPool.submit(task);
        Long sum = submit.get();

        long endTime = System.currentTimeMillis();
        System.out.println(sum + ":" + (endTime-startTime));
    }

    public static void test3(){
        long sum = 0L;
        long startTime = System.currentTimeMillis();
        sum = LongStream.rangeClosed(0,10_0000_0000L).parallel().reduce(0,Long::sum);
        long endTime = System.currentTimeMillis();
        System.out.println(sum + ":" + (endTime-startTime));

    }
}

15、异步回调

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

package Futrure;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

//异步执行
//成功回调
//失败回调
public class Demo01 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 没有返回值的runAsync 异步回调
        CompletableFuture<Void> objectCompletableFuture = CompletableFuture.runAsync(()->{
            try {
                TimeUnit.SECONDS.sleep(2);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "runAsync => Void");
        });
        System.out.println("1111");
        objectCompletableFuture.get();//获取阻塞执行结果
        /*1111
        ForkJoinPool.commonPool-worker-1runAsync => Void*/
        
//        有返回值的 supplyAsync 异步回调
        CompletableFuture<Integer> uCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "supplyAsync=>Integer");
            return 1024;
        });
        
//        可以理解为,上面的是异步请求的方法体,下面为ajax的success:function(){}和error:function(){}
        uCompletableFuture.whenComplete((t,u)->{
            System.out.println(t);//正常的返回结果
            System.out.println(u);//报错的错误信息
        }).exceptionally((e)->{
            System.out.println(e.getMessage());
            return 233;//可以获取到错误的返回结果
        });

    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值