JUC编发编程 狂神第二讲

1、读写锁

A ReadWriteLock维护一对关联的locks ,一个用于只读操作,一个用于写入。
read lock可以由多个阅读器线程同时进行,只要没有作者。 write lock是独家的。

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

        for (int i = 0; i < 5; i++) {
            final int temp=i;
            new Thread(()->{
                myCache.put(""+temp,""+temp);
            },""+i).start();
        }

        for (int i = 0; i < 5; i++) {
            final int temp=i;
            new Thread(()->{
                myCache.get(""+temp);
            }).start();
        }
    }
}
/**
 * 自定义缓存
 */
class MyCache{
    private volatile Map<String,Object> map = new HashMap<>();

    //存  写
    public void put(String key,Object value){
        System.out.println(Thread.currentThread().getName()+" 写入"+key);
        map.put(key, value);
        System.out.println(Thread.currentThread().getName()+" 写入ok");
    }

    //取  读
    public void get(String key){
        System.out.println(Thread.currentThread().getName()+" 读取"+key);
        map.get(key);
        System.out.println(Thread.currentThread().getName()+" 读取ok");
    }
}

class MyCacheLock {
    private volatile Map<String,Object> map = new HashMap<>();
    //读写锁:更加细粒度的控制
    private ReadWriteLock lock = new ReentrantReadWriteLock();
//    private Lock lock = new ReentrantLock();

    //写     只希望同时有一个线程写
    public void put(String key,Object value){
        lock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getName()+" 写入"+key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName()+" 写入ok");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.writeLock().unlock();
        }

    }

    //取  读
    public void get(String key){
        lock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+" 读取"+key);
            map.get(key);
            System.out.println(Thread.currentThread().getName()+" 读取ok");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.readLock().unlock();
        }
    }
}

上锁前的结果:

0 写入0
1 写入1
2 写入2
1 写入ok
0 写入ok
2 写入ok
Thread-0 读取0
Thread-1 读取1
Thread-0 读取ok
Thread-1 读取ok
Thread-2 读取2
Thread-2 读取ok

上锁后的结果: 写的线程同时只能存在一条

0 写入0
0 写入ok
1 写入1
1 写入ok
2 写入2
2 写入ok
Thread-0 读取0
Thread-1 读取1
Thread-0 读取ok
Thread-2 读取2
Thread-2 读取ok
Thread-1 读取ok

读写锁ReadWriterLock和Lock区别:

  1. 读写锁会在所有写入完成后才可以读取,Lock锁不一定
  2. 读写锁的读锁可以同时存在多条线程,但Lock锁在读取时,只能有一条

2.阻塞队列(BlockingQueue)

在这里插入图片描述
Queue下面有三个:

  1. Deque 双端队列
  2. BlockingQueue阻塞队列
  3. AbstractQueue 非阻塞队列

FIFO:先进先出

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

使用阻塞队列:多线程并发处理,线程池!

四组API

  1. 抛出异常
  2. 不抛出异常
  3. 阻塞 等待
  4. 等待

在这里插入图片描述
add offer put offer(Object , long , TimeUnit)
remove poll take poll(long , TimeUnit)
element peek

方法抛出异常不抛出异常一直阻塞等待可设置等待时间
添加addofferputoffer(Object , long , TimeUnit)
移除removepolltakepoll(long , TimeUnit)
检查队首元素elementpeek

public class Test {
    public static void main(String[] args) throws InterruptedException {
//        test1();
//        test2();
        test3();
//        test4();
    }
    /**
     * 抛出异常
     */
    public static void test1(){
        //队列大小
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

        System.out.println(blockingQueue.add("a"));
        System.out.println(blockingQueue.add("b"));
        System.out.println(blockingQueue.add("c"));

        //抛出队列已满    java.lang.IllegalStateException
//        System.out.println(blockingQueue.add("d"));

        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        //抛出异常java.util.NoSuchElementException  没有元素
//        System.out.println(blockingQueue.remove());


        //java.util.NoSuchElementException
        System.out.println(blockingQueue.element());
        /**
         * 结果:
         * true
         * true
         * true
         * a
         * b
         * c
         * Exception in thread "main" java.util.NoSuchElementException
         */
    }

    /**
     * 有返回值,没有异常
     */
    public static void test2(){
        //队列大小
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
        //不抛出异常 返回false
        System.out.println(blockingQueue.offer("d"));
        System.out.println(blockingQueue.peek());
        System.out.println("===========");

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        //不抛出异常 返回null
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.peek());
        /**
         * 结果:
         * true
         * true
         * true
         * false
         * a
         * ===========
         * a
         * b
         * c
         * null
         * null
         */
    }

    /***
     * 等待,一直阻塞
     */
    public static void test3() throws InterruptedException {
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");

        //一直阻塞
//        blockingQueue.put("d");

        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        //一直阻塞
        System.out.println(blockingQueue.take());
        /**
         * 结果:
         * a
         * b
         * c
         * ... ...(一直等待)
         */
    }

    /**
     * 等待,阻塞(等待超时)
     */
    public static void test4() throws InterruptedException {
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

        blockingQueue.offer("1");
        blockingQueue.offer("2");
        blockingQueue.offer("3");
        blockingQueue.offer("4", 2,TimeUnit.SECONDS);

        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll(2,TimeUnit.SECONDS));
        /**
         * 结果:
         * 1
         * 2
         * 3
         * null
         */
    }
}

SynchronizeQueue 同步队列
同步队列和BlockingQueue不一样,SynchronizeQueue不存储元素
put一个元素,必须从里面先take取出来,否则不能在put进去值

//同步队列
public class SynchronizeQueueDemo {
    public static void main(String[] args) {
        //同步队列
        BlockingQueue blockingQueue = new SynchronousQueue();

        new Thread(()->{

            try {
                System.out.println(Thread.currentThread().getName()+" put 1");
                blockingQueue.put("1");
                System.out.println(Thread.currentThread().getName()+" put 2");
                blockingQueue.put("2");
                System.out.println(Thread.currentThread().getName()+" put 3");
                blockingQueue.put("3");
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"1").start();

        new Thread(()->{

            try {
                System.out.println(Thread.currentThread().getName()+" "+blockingQueue.take());
                System.out.println(Thread.currentThread().getName()+" "+blockingQueue.take());
                System.out.println(Thread.currentThread().getName()+" "+blockingQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"2").start();
    }
}

3、线程池(重点)

三大方法,七大参数,四种拒绝策略

池化技术
程序的运行,本质:占用系统的资源,优化资源的使用 = 》池化技术
线程池,连接池,内存池,对象池

池化技术:事先准备好资源
线程池的优点:

  1. 降低资源的消耗
  2. 提高响应的速度
  3. 方便管理

线程复用、可以控制最大并发数,管理线程
创建线程注意的地方:
在这里插入图片描述

三大方法

源码分析:

        ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
        ExecutorService threadPool = Executors.newFixedThreadPool(5);//创建一个固定的线程池的大小
        ExecutorService threadPool = Executors.newCachedThreadPool();//可以伸缩的
  try {
            for (int i = 0; i < 10; i++) {
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池
            threadPool.shutdown();
        }




    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

本质:ThreadPoolExecutor

七大参数(ThreadPoolExecutor 构造方法中的参数)


    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;
    }

四种拒绝策略

/**手动创建一个线程池
 * Executors  工具类  3大方法
 * 使用线程池来创建线程
 */
public class Demo01 {
    public static void main(String[] args) {
        ExecutorService threadPool = new ThreadPoolExecutor(2,
                5,2,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
//                new ThreadPoolExecutor.CallerRunsPolicy());  //线程满了,还有请求进来,不处理这个请求,哪来的去哪里,给main处理
//                new ThreadPoolExecutor.AbortPolicy());  //线程满了,还有请求进来,不处理这个请求,抛出异常
//                new ThreadPoolExecutor.DiscardPolicy());  //线程满了,还有请求进来,丢掉任务,不抛出异常
                new ThreadPoolExecutor.DiscardOldestPolicy());  //线程满了,还有请求进来,尝试和最早的请求竞争,不行就抛弃,不抛出异常

        try {
            for (int i = 0; i < 10; i++) {
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭线程池
            threadPool.shutdown();
        }

    }
}

小结:

最大线程应该如何设置:

  1. CPU 密集型,电脑几核就定义为几
    // CPU核数
    System.out.println(Runtime.getRuntime().availableProcessors());
  2. IO 密集型, 判断你程序中十分耗 IO 的线程

4、四大函数式接口(必学掌握)

函数式接口
lambda表达式

泛型,枚举,反射
lambda表达式,链式编程,函数式接口,Stream流式计算

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

四大原生函数式接口:

1. Function 函数式接口


/**
 * Function     函数型接口
 *  只要是函数式接口就可以  用lambda表达式简化
 */
public class Demo01 {
    public static void main(String[] args) {
        //工具类   一个输入参数  一个输出参数
//        Function<String, String> function = new Function<String, String>() {
//            @Override
//            public String apply(String o) {
//                return o;
//            }
//        };

        //lambda表达式
        Function<String, String> function = (str)->{return str;};

        System.out.println(function.apply("qwe"));
    }
}

2. predicate 断定型接口

public class Demo02 {
    public static void main(String[] args) {
//        Predicate predicate = new Predicate<String>() {
//            @Override
//            public boolean test(String s) {
//                return s.isEmpty();
//            }
//        };

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

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

3. Consumer 消费型接口

//  消费型接口
public class Demo03 {
    public static void main(String[] args) {
//        Consumer<String> consumer = new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println("消费了 "+s);
//            }
//        };

        Consumer<String> consumer = (s)->{System.out.println("消费了 "+s);};

        consumer.accept("world");
    }
}

4. supplier 供给型接口

/**
 * supplier 供给型接口
 */
public class Demo04 {
    public static void main(String[] args) {
//        Supplier<String> supplier = new Supplier<String>() {
//            @Override
//            public String get() {
//                return "world";
//            }
//        };

        Supplier<String> supplier = ()->{return "world";};

        System.out.println(supplier.get());
    }
}

5、Stream流式计算

什么是Stream流式计算

 public static void main(String[] args) {
        User u1 = new User(1, "a", 11);
        User u2 = new User(2, "b", 22);
        User u3 = new User(3, "c", 33);
        User u4 = new User(4, "d", 44);
        User u5 = new User(5, "e", 55);

        List<User> list = Arrays.asList(u1, u2,u3,u4,u5);

        //链式编程  lambda表达式 函数式接口 Stream流式计算
        list.stream()
                //    Stream<T> filter(Predicate<? super T> predicate);
                //      boolean test(T t);
                .filter((u)->{return u.getId()%2==1;})
                .filter(u->{ return u.getAge()>30;})
                //    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
                //    R apply(T t);
                .map(u->{return u.getName().toUpperCase();})
                //    Stream<T> sorted(Comparator<? super T> comparator);
                //    int compare(T o1, T o2);
                .sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
                //    Stream<T> limit(long maxSize);
                .limit(1)
                .forEach(System.out::println);
    }

6、ForkJoin

大数据量

ForkJoin 分支合并
并行执行任务
大任务分成小任务 分而治之

工作窃取
去拿其他多的还没有执行的
在这里插入图片描述

在这里插入图片描述

/**人生自信两百年,会当击水三千里
 * 求和计算任务
 *  3000    6000(ForkJoin)      9000(Stream并行流)
 *
 *  如何使用ForkJoin
 *  1.ForkJoinPool  执行
 *  2.计算任务ForkJoinPool.execute(ForkJoinTask task)
 *  3.计算类要继承 ForkJoinTask
 */
public class ForkJoinDemo extends RecursiveTask<Long> {//RecursiveTask<V> extends ForkJoinTask<V>
    long start;
    long end;

    //临界值
    long temp = 10000L;

    public ForkJoinDemo(long start, long end) {
        this.start = start;
        this.end = end;
    }

    //计算的返回值就是 long
    @Override
    protected Long compute() {
        if((end - start) > temp){
            //ForkJoin
            //分支合并计算
            long middle = start + (end - start) /2 ;
            ForkJoinDemo task1 = new ForkJoinDemo(start, middle);
            task1.fork();   //把线程压入线程队列
            ForkJoinDemo task2 = new ForkJoinDemo(middle+1, end);
            task2.fork();   //把线程压入线程队列

            return task1.join() + task2.join();
        }else{
            long sum=0;
            for (long i = start; i <= end; i++) {
                sum+=i;
            }
            return sum;
        }
    }
}
   ForkJoinPool forkJoinPool = new ForkJoinPool();
   ForkJoinDemo forkJoinDemo = new ForkJoinDemo(1, 10_0000_0000);
   ForkJoinTask<Long> submit = forkJoinPool.submit(forkJoinDemo);
       sum = submit.get();

Test:

public class Test {
    public static void main(String[] args) {
        test1();
        test2();
        test3();
    }

    public static void test1(){
        long sum=0;
        long start = System.currentTimeMillis();
        for (int i = 1; i <= 10_0000_0000; i++) {
            sum+=i;
        }
        long end = System.currentTimeMillis();
        System.out.println(sum);
        System.out.println("==> "+(end-start));
    }

    public static void test2(){
        long sum=0;
        long start = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool();

        ForkJoinDemo forkJoinDemo = new ForkJoinDemo(1, 10_0000_0000);

        ForkJoinTask<Long> submit = forkJoinPool.submit(forkJoinDemo);

        try {
            sum = submit.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println(sum);
        System.out.println("==> "+(end-start));
    }

    //Stream并行流 ()
    public static void test3(){
        long sum=0;
        long start = System.currentTimeMillis();

        sum = LongStream.rangeClosed(0L, 10_0000_0000L).parallel().reduce(0, Long::sum);

        long end = System.currentTimeMillis();
        System.out.println(sum);
        System.out.println("==> "+(end-start));
    }
}

7、异步回调

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

在这里插入图片描述

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

        //有返回值的 runAsync 异步回调
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName()+" => Void");
            int i=1/0;
            return 1024;
        });
        //t: 正确返回结果
        //u: 错误信息
        Integer integer = completableFuture.whenComplete((t, u) -> {
            System.out.println("t: " + t);
            System.out.println("u: " + u);
        }).exceptionally((e) -> {
            System.out.println(e.getMessage());
            return 233;
        }).get();

        //回去错误的返回值
        System.out.println(integer);
    }
}

ForkJoinPool.commonPool-worker-9 => Void
t: null
u: java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
java.lang.ArithmeticException: / by zero
233


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值