JUC02

JUC02

8.读写锁

package com.mjh.rw;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/*
独占锁(写锁)一次只能被一个线程占有
共享锁(读锁)多个线程可以同时占有
 ReadWriteLock
 读-读  可以共存
 读-写  不能共存
 写-写  不能共存
*/
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyCache1 myCache = new MyCache1();
        //写入
        for (int i = 0; i <=5 ; i++) {
            final int temp=i;
            new Thread(()->{
                myCache.put(temp+"",temp+"");
            },String.valueOf(i)).start();
        }

        //读取
        for (int i = 0; i <=5 ; i++) {
            final int temp=i;
            new Thread(()->{
                myCache.get(temp+"");
            },String.valueOf(i)).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()+" 写入成功");
    }

    //取,读
    public void get(String key){
        System.out.println(Thread.currentThread().getName()+" 读物"+key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName()+" 读取成功");
    }
}

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

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

            System.out.println(Thread.currentThread().getName()+" 写入"+key);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+" 写入成功");
        } 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()+" 读取成功");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }

    }
}

9.阻塞队列

阻塞队列


  • BlockingQueue  不是新东西
    

什么情况下我们会使用阻塞队列?多线程并发处理,线程池

学会使用队列

添加 移除

四组API

1.抛出异常

package com.mjh.bq;

import java.security.spec.RSAOtherPrimeInfo;
import java.util.concurrent.ArrayBlockingQueue;
//抛出异常
public class Demo {
    public static void main(String[] args) {
        test1();
    }
    public static void test1(){
        //队列的大小
        ArrayBlockingQueue<Object> 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: Queue full
       // System.out.println(blockingQueue.add("D"));
        System.out.println(blockingQueue.element());//查询队首元素
        System.out.println("======================");

        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());

        //java.util.NoSuchElementException
       // System.out.println(blockingQueue.remove());
    }
}

2.不会抛出异常,返回一个特殊值

//不会抛出异常,返回一个特殊值
    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"));

       // System.out.println(blockingQueue.offer("A"));//false  不抛出异常
        System.out.println(blockingQueue.peek());//查询队首元素
        System.out.println("=======================");
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());

        // System.out.println(blockingQueue.poll());// null  不抛出异常

    }

3.阻塞等待

/*
阻塞等待
 */
public static void test3() throws InterruptedException {
    //队列大小
    ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

    blockingQueue.put("A");
    blockingQueue.put("B");
    blockingQueue.put("C");
    //blockingQueue.put("C");//队列没有位置了,一直等待

    System.out.println(blockingQueue.take());
    System.out.println(blockingQueue.take());
    System.out.println(blockingQueue.take());
   // System.out.println(blockingQueue.take()); //没有这个元素,一直等待
}

4.超时等待

/*
超时等待
 */
public static void test4() throws InterruptedException {
    //队列的大小
    ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

    System.out.println(blockingQueue.offer("A"));
    System.out.println(blockingQueue.offer("B"));
    System.out.println(blockingQueue.offer("C"));
    System.out.println(blockingQueue.offer("D",5, TimeUnit.SECONDS));//等待超过5秒就退出

    System.out.println("======================");
    System.out.println(blockingQueue.poll());
    System.out.println(blockingQueue.poll());
    System.out.println(blockingQueue.poll());
    System.out.println(blockingQueue.poll(5,TimeUnit.SECONDS));//等待超过5秒就退出

}

SynchronousQueue 同步队列

package com.mjh.bq;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * 同步队列
 * 和其他的BlockingQueue不一样,SynchronousQueue不存储元素
 * put了一个元素,必须从里面先take取出来,否则不能再put进去值
 */
public class SynchronousQueueDemo {
    public static void main(String[] args) {
        BlockingQueue<String> 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 (InterruptedException e) {
                e.printStackTrace();
            }
        },"T1").start();

        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+"=>"+ blockingQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+"=>"+ blockingQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+"=>"+ blockingQueue.take());


            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"T2").start();
    }
}

10.线程池(重点)

线程池技术:三大方法、7大参数、4种拒绝策略

池化技术

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

线程池、连接池、内存池、对象池。。。。创建、销毁,十分浪费资源

池化技术:事先准备好一些资源,有人要用,就来我这里拿,用完之后还给我。

线程池的好处:

1、降低资源的消耗

2、提高响应的速度

3、方便管理

线程复用、可以控制最大并发数、管理线程

线程池:三大方法

package com.mjh.pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//Executors 工具类
public class Demo {
    public static void main(String[] args) {
       ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
        //ExecutorService threadPool = Executors.newFixedThreadPool(5);//创建一个固定的线程池大小
        //ExecutorService threadPool = Executors.newCachedThreadPool();//可伸缩的,遇强则强,遇弱则弱

        try {
            for (int i = 0; i <100 ; i++) {
                //使用了线程池之后,使用线程池来创建对象
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" OK");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }
    }
}

7大参数

源码分析

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
      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.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

手动创建

package com.mjh.pool;

import java.util.concurrent.*;

//Executors 工具类

/*
new ThreadPoolExecutor.AbortPolicy());//银行满了,还有人进来,有权不处理这个人的业务,抛出异常
new ThreadPoolExecutor.CallerRunsPolicy());//哪里来的回哪里去
new ThreadPoolExecutor.DiscardPolicy());//队列满了,剩余自动丢弃,不会抛出异常
new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试去和最早的竞争,不会抛出异常
 */

public class Demo {
    public static void main(String[] args) {
   
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                2,//核心窗口
                5,//最大窗口数量
                3,//超时时间   银行有五个窗口开着,今天人少,有三个窗口是空闲的,这三个窗口在三秒后关闭
                TimeUnit.SECONDS,//超时单元
                new LinkedBlockingDeque<>(3),//候客区
                Executors.defaultThreadFactory(),//线程工厂,一般不用动
                new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试去和最早的竞争,不会抛出异常

        try {
            //最大承载:Deque+max
            //超过了RejectedExecutionException 异常
            for (int i = 0; i <9; i++) {
                //使用了线程池之后,使用线程池来创建对象
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" OK");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }
    }
}

4 大拒绝策略

new ThreadPoolExecutor.AbortPolicy());//银行满了,还有人进来,有权不处理这个人的业务,抛出异常
new ThreadPoolExecutor.CallerRunsPolicy());//哪里来的回哪里去
new ThreadPoolExecutor.DiscardPolicy());//队列满了,剩余自动丢弃,不会抛出异常
new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试去和最早的竞争,不会抛出异常

IO密集型和CPU密集型

最大线程到底该如何定义

package com.mjh.pool;

import java.util.concurrent.*;

//Executors 工具类

public class Demo {
    public static void main(String[] args) {
   
/**
 * 自定义线程池 工作中使用  ThreadPoolExecutor
 *
 * 最大线程到底该如何定义
 * 1.cpu 密集型,几核,就是几,可以保持CPU的效率最高!
 * 2.IO  密集型  > 判断你程序中十分好IO的线程
 * 程序   15大型任务   IO十分占用资源
 */
        System.out.println(Runtime.getRuntime().availableProcessors());
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                2,//核心窗口
               Runtime.getRuntime().availableProcessors(),//可利用处理器
                3,//超时时间   银行有五个窗口开着,今天人少,有三个窗口是空闲的,这三个窗口在三秒后关闭
                TimeUnit.SECONDS,//超时单元
                new LinkedBlockingDeque<>(3),//候客区
                Executors.defaultThreadFactory(),//线程工厂,一般不用动
                new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试去和最早的竞争,不会抛出异常

        try {
            //最大承载:Deque+max
            //超过了RejectedExecutionException 异常
            for (int i = 0; i <9; i++) {
                //使用了线程池之后,使用线程池来创建对象
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" OK");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }
    }
}


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

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

函数式接口:只有一个方法的接口

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
//传统程序员:泛型  枚举  反射
//超级多的@FunctionalInterface
//简化编程模型,在新版本的框架底层大量使用
//foreach(消费者类函数式接口)

Function函数式接口

package com.mjh.function;

import java.util.function.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 str) {
              return str;
          }
      };*/

        Function<String,String> function=  (str)->{return str;};
        System.out.println(function.apply("abc"));
    }
}

Predicate 断定型接口:只有一个传入参数,返回值只能是布尔值

package com.mjh.function;

import java.util.function.Predicate;

/**
 * Predicate断定型接口  只有一个传入参数,返回值只能是布尔值
 */
public class Demo02 {
    public static void main(String[] args) {
       /* Predicate<String> predicate = new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.isEmpty();
            }
        };*/

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

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

Consumer 消费型接口:只有一个传入参数,没有返回值

package com.mjh.function;

import java.util.function.Consumer;

/**
 *  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("ccccgfd");
    }
}

Suplier 供给型接口:没有参数,只有返回值

package com.mjh.function;

import java.util.function.Supplier;

public class Demo04 {
    public static void main(String[] args) {
      /* Supplier<String> supplier = new Supplier<String>() {
            @Override
            public String  get() {
                System.out.println("get()");
                return "1024";
            }
        };
*/
        Supplier<String> supplier =()->{return "1024";};
                System.out.println(supplier.get());
    }
}

作用:

简化编程,提高效率

12.Stream 流式计算

package com.mjh.stream;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 *题目要求:一分钟内完成此题,只能用一行代码实现!
 * 现在5个用户,筛选:
 * 1.ID必须是偶数
 * 2.年龄必须大于23岁
 * 3.用户转为大写字母
 * 4.用户名字倒着排序
 * 5.只输出一个用户
 */
public class StreamTest {
    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",25);
        User u6 =new User(8,"f",28);
        //集合就是存储
       List<User> list= Arrays.asList(u1,u2,u3,u4,u5,u6);

       //计算交给Steam流
        // lambda表达式,链式编程,函数式接口,Stream流式计算
        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);


    }
}

13 .ForkJoin

什么ForkJoin

使用场景:并行执行任务,提高效率,大数据量!

大数据:Map Reduce(把大任务拆分成小任务)

ForkJoin 特点

工作窃取

这里面维护都是双端队列

14.异步回调

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

package com.mjh.future;

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

/**  异步回调  CompletableFuture/Ajax
 * 异步执行
 * 成功回调
 * 失败回调
 */
public class Demo {
    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()+"runAsync=>Void");
        });
        System.out.println("aaaaa");
        completableFuture.get();//阻塞获取执行结果
        */

        //有返回值的supplyAsync  异步回调
        //ajax,  成功和失败的回调
        //返回的是错误的信息

        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName()+" supplyAsync=>Integer");

            int i=10/0;
            return 1024;
        });

        System.out.println(completableFuture.whenComplete((t,u)->{
            System.out.println("t=>"+t);//正常的返回结果
            System.out.println("u=>"+u);//错误信息,java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
        }).exceptionally((e)->{
            System.out.println(e.getMessage());
            return 404;//可以获取到的错误的返回结果
                }).get());

    }
}
posted @ 2020-09-30 20:49  林森001  阅读(84)  评论(0编辑  收藏  举报