JUC——Day02

JUC Day02

文章总结自B站狂神说JAVA

1.Callable

优点:可以有返回值,可以抛出异常。
代码测试:

/**
 * @date 2020/7/27 8:04
 * callable 测试
 */
public class CallableDemo01 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        启动callable
        MyThread myThread = new MyThread();
//        适配类
        FutureTask futureTask = new FutureTask(myThread);
//        启动线程
        new Thread(futureTask,"A").start(); // 有缓存
//        获取callable的返回接口
        Integer integer = (Integer) futureTask.get();//get方法可能会参送阻塞,一般放到最后,或者使用异步进行处理.
        System.out.println(integer);
    }
}

class MyThread implements Callable<Integer >{

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

}

2. 常用的辅助类

2.1 CountDownLatch

类似于减法计数器,设定一个总数,每执行一个线程-1;当普通线程数量归零时执行指定的线程。


/**
 * @date 2020/7/27 8:23
 * 辅助类:
 *  1. CountDownLatch 减法计数器
 */
public class CountDownLatchDemo01 {
    public static void main(String[] args) {
//        设定线程的总数为 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();
            },String.valueOf(i)).start();
        }

        try {
//            等待计数器归零再向下执行.
            countDownLatch.await();
            System.out.println("线程全部执行完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

2.2 CyclicBarrier

类似与一个加法计数器,当线程增加到达指定的值时执行线程。

/**
 * @date 2020/7/27 8:32
 * 辅助类:
 * 2. CyclicBarrier 加法计数器
 */
public class CyclicBarrierDemo01 {
    public static void main(String[] args) {

//        创建CyclicBarrier
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("线程达到指定的值,我开始运行嗷");
        });

        for (int i = 0; i <= 10; i++) {
            new Thread(()->{
                try {
                    System.out.println("第"+Thread.currentThread().getName());
//                    当线程数量符合条件时执行.
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}

2.3 Semaphore

类似于一个通行证,用来指定最多运行多少个线程, 每当一个线程运行完毕时,正在等待的线程再运行。一般用来限流,多个线程共享资源。

/**
 * @date 2020/7/27 8:47
 * 辅助类:
 * 3. Semaphore 通行证
 */
public class SemaphoreDemo01 {
    public static void main(String[] args) {
//        最多同时运行的线程数量
        Semaphore semaphore = new Semaphore(3);
        for (int i = 6; i > 0; i--) {
            new Thread(()->{
                try {
//                   得到
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"`启动");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName()+"`dead");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
//                    释放
                    semaphore.release();
                }
            },String.valueOf(i)).start();
        }
    }
}

3. 读写锁

如果写入的过程中其它的线程也执行写入,当前写入线程就会变慢,所以使用读写锁:读可以被多个线程同时读,写的时候只能由一个线程写。独占锁:只有一个线程能够使用;共享锁:多个线程共享锁。读锁是共享锁,写锁是独占锁。


/**
 * @date 2020/7/27 8:57
 * 读写锁
 */
public class ReadWriteLockDemo01 {
    public static void main(String[] args) {
        MyCache myCache = new MyCache();


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

//        读取
        for (int i = 0; i < 5; i++) {
            final int temp = i;
            myCache.get(temp+"");
            new Thread(()->{},String.valueOf(i)).start();
        }
    }
}
class MyCache{
    private volatile Map<String ,Object> map = new HashMap<>();
//    创建读写锁对象:
    private ReadWriteLock lock = new ReentrantReadWriteLock();


//    存->写
    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()+"------------写入完毕------------------");
        }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);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName()+"------------读取完毕------------------");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.readLock().unlock();
        }
    }
}

4.阻塞队列

4.1BlockingQueue

  1. 抛出异常:当队列满了或者为空的时候再次执行方法会抛出异常
/**
 * @date 2020/7/27 9:21
 * BlockingQueue  抛出异常 
 */
public class Demo01 {
    public static void main(String[] args) {
        test1();
    }
    public  static  void test1(){
//        参送为 队列的大小
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);

        System.out.println(arrayBlockingQueue.add("A"));
        System.out.println(arrayBlockingQueue.add("B"));
        System.out.println(arrayBlockingQueue.add("C"));

//        获取队列首位
        System.out.println(arrayBlockingQueue.element());

//      java.lang.IllegalStateException: Queue full 队列满了
        System.out.println(arrayBlockingQueue.add("D"));

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

//      java.lang.IllegalStateException: Queue full 队列为空
        System.out.println(arrayBlockingQueue.remove());

    }
}

  1. 有返回值不抛出异常:当队列满了再执行添加会返回false,队列为空再执行移除会返回null
/**
 * @date 2020/7/27 9:21
 * BlockingQueue  不抛出异常 有返回值
 */
public class Demo02 {
    public static void main(String[] args) {
        test2();
    }
    public  static  void test2(){
//        参送为 队列的大小
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);

        System.out.println(arrayBlockingQueue.offer("A"));
        System.out.println(arrayBlockingQueue.offer("B"));
        System.out.println(arrayBlockingQueue.offer("C"));

//        获取队列首位
        System.out.println(arrayBlockingQueue.peek());


//       返回 false 不抛出异常
        System.out.println(arrayBlockingQueue.offer("D"));

        System.out.println(arrayBlockingQueue.poll());
        System.out.println(arrayBlockingQueue.poll());
        System.out.println(arrayBlockingQueue.poll());

//      队列为空返回 null
        System.out.println(arrayBlockingQueue.poll());
    }
}

  1. 一直等待处于阻塞:当队列满了,会一直等待直到能够进去为止;
/**
 * @date 2020/7/27 9:21
 * BlockingQueue  一直等待 阻塞
 */
public class Demo03 {
    public static void main(String[] args) {
      test3();
    }
    public  static  void test3() {
//        参送为 队列的大小
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);

//        存----> 存不进去会一直阻塞,直到进去为止
        try {
            arrayBlockingQueue.put("a");
            arrayBlockingQueue.put("b");
            arrayBlockingQueue.put("c");
            arrayBlockingQueue.put("d");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


//       取--> 当取不到是也会一直阻塞,直到取到为止
        try {
            System.out.println(arrayBlockingQueue.take());
            System.out.println(arrayBlockingQueue.take());
            System.out.println(arrayBlockingQueue.take());
            System.out.println(arrayBlockingQueue.take());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
       
    }
}
  1. 超时退出等待:设定一个时间,等到超过时间就退出不再等待。
/**
 * @date 2020/7/27 9:21
 * BlockingQueue  一超退出等待
 */
public class Demo04 {
    public static void main(String[] args) {
      test4();
    }
    public  static  void test4() {
//        参送为 队列的大小
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);

//        存
        arrayBlockingQueue.offer("A");
        arrayBlockingQueue.offer("B");
        arrayBlockingQueue.offer("C");
        try {
//            设置超时时间超过时间就直接退出
            arrayBlockingQueue.offer("D",2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        arrayBlockingQueue.poll();
        arrayBlockingQueue.poll();
        arrayBlockingQueue.poll();
        try {
//            设置超时时间超过时间就直接退出
            arrayBlockingQueue.poll(2,TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

4.2 SynchornizedQueue

同步队列,没有容量。必须进去一个元素等待取出来再往里面放元素。

/**
 * @date 2020/7/27 10:13
 * 同步队列Synchronized,队列中同时最多存在一个元素,必须先取出来才能再次存.
 */
public class Demo01 {
    public static void main(String[] args) {
        BlockingQueue<String> synchronousQueue = new SynchronousQueue();
        new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + " -> put 1");
                synchronousQueue.put("1");
                System.out.println(Thread.currentThread().getName() + " -> put 2");
                synchronousQueue.put("2");
                System.out.println(Thread.currentThread().getName() + " -> put 3");
                synchronousQueue.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T1").start();

        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() +synchronousQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() +synchronousQueue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() +synchronousQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T1").start();
    }
}

5. 线程池

事先奖准备好的资源放在一块,用就拿走,用完就换回来。
优势:

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

5.1 三大方法

  1. newSingleThreadExecutor 单一线程池,只能由一个线程
/**
 * @date 2020/7/27 10:35
 * Executors:
 * 1. newSingleThreadExecutor()
 */
public class Demo01 {
    public static void main(String[] args) {
//        得到一个线程的线程池
        ExecutorService service = Executors.newSingleThreadExecutor();
        try {
//         使用线程池创建线程
            for (int i = 0; i < 10; i++) {
                service.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"----------------------");
                });
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
//        程序结束关闭线程池
            service.shutdown();

        }
    }
}
  1. newFixedThreadPool 固定线程池,指定固定的线程数量
/**
 * @date 2020/7/27 10:35
 * Executors
 * 2. newFixedThreadPool
 */
public class Demo02 {
    public static void main(String[] args) {
//        得到固定数量的线程池
        ExecutorService service = Executors.newFixedThreadPool(5);
        try {
//         使用线程池创建线程
            for (int i = 0; i < 10; i++) {
                service.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"----------------------");
                });
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
//        程序结束关闭线程池
            service.shutdown();
        }
    }
}

  1. newCachedThreadPool 根据情况来设定线程数量
/**
 * @date 2020/7/27 10:35
 * Executors
 * 3. newCachedThreadPool
 */
public class Demo03 {
    public static void main(String[] args) {
//        根据实际情况得到线程的数量
        ExecutorService service = Executors.newCachedThreadPool();
        try {
//         使用线程池创建线程
            for (int i = 0; i < 10; i++) {
                service.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"----------------------");
                });
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
//        程序结束关闭线程池
            service.shutdown();
        }
    }
}

5.2 七大参数

上述三种创建线程池的方法实际上都是调用的相同的方法ThreadPoolExecutor

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory
                              ThreadPoolExecutor ) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }

参数

  1. corePoolSize 核心线程池大小
  2. maximumPoolSize 最大核心线程池大小
  3. keepAliveTime 超时释放
  4. unit 超时单位
  5. workQueue 阻塞队列
  6. threadFactory 线程工厂
  7. defaultHandler 拒绝策略

5.3 自定义线程池

阿里巴巴开发手册推荐使用底层的ThreadPoolExecutor方法来创建线程。

/**
 * @date 2020/7/27 14:01
 * 自定义线程池
 */
public class Demo04 {
    public static void main(String[] args) {
        ExecutorService service = new ThreadPoolExecutor(
                2,
                Runtime.getRuntime().availableProcessors(), // 获取cpu核心数
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        try {
//            线程最大承受 =  最大线程数量 +  队列数量
            for (int i = 0; i < 9; i++) {
                service.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"---->");
                });
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            service.shutdown();
        }
    }
}

5.4 四种拒绝策略

5.4.1 AbortPolicy

默认的拒绝策略,当线程数量超过最大的承受范围时会抛出异常。

java.util.concurrent.RejectedExecutionException: Task pool.Demo04$$Lambda$1/558638686@6d03e736 rejected from java.util.concurrent.ThreadPoolExecutor@568db2f2[Running, pool size = 5, active threads = 0, queued tasks = 0, completed tasks = 8]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
	at pool.Demo04.main(Demo04.java:21)
5.4.2 CallerRunsPolicy

当超过线程池的最大承受范围时,由进入时的线程执行。

pool-1-thread-2---->
pool-1-thread-3---->
pool-1-thread-1---->
pool-1-thread-3---->
main---->
pool-1-thread-2---->
pool-1-thread-1---->
pool-1-thread-4---->
pool-1-thread-5---->
5.4.3 DiscardPolicy

队列满了会丢掉任务但是不会抛出异常。

pool-1-thread-2---->
pool-1-thread-3---->
pool-1-thread-1---->
pool-1-thread-3---->
pool-1-thread-1---->
pool-1-thread-2---->
pool-1-thread-5---->
pool-1-thread-4----> 
5.4.4 DiscardOldestPolicy

队列满了尝试去和第一个调用的线程竞争,也不会去抛出异常。

5.5 CPU密集型与IO密集型

在创建线程池时,需要指定最大核心线程池大小;指定方法分为IO密集型和CPU密集型。

  1. CPU密集型:几核就设定为几,获取CPU核心数:Runtime.getRuntime().availableProcessors()
  2. IO密集型:因为IO消耗资源大,所以在设定核心线程池大小时要大于IO的的线程数量就行。

6. 函数式接口

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

6.1 Function -> 函数型接口

有两个参数,输入值和返回值。

/**
 * @date 2020/7/27 14:34
 * 函数型接口 --- function
 */
public class Demo01 {
    public static void main(String[] args) {

//       工具类,返回输入的值,有一个输入参数,一个输出参数。
        Function function =  new Function<String ,String >() {
            @Override
            public String apply(String s) {
                return s;
            }
        };


//        lambda 表达式简写函数型接口。
        Function function1 = (str)->{return str;};

        System.out.println(function1.apply("1"));
        System.out.println(function.apply("12342"));
    }
}

6.2 Predicate -> 断定型接口

有一个输入参数,返回值为布尔值。

/**
 * @date 2020/7/27 14:42
 * 断定型接口 --- Predicate
 *   有一个输入参数,返回一个布尔值。
 */
public class Demo02 {
    public static void main(String[] args) {
//        判断字符串是否为空
        Predicate predicate = new Predicate<String>(){
            @Override
            public boolean test(String o) {
                return o.isEmpty();
            }
        };

//        lambda 简化断定型接口
        Predicate<String > predicate1 = (str) ->{return str.isEmpty()};
        System.out.println(predicate.test("1412"));

    }
}

6.3 Consumer -> 消费型接口

没有返回值只有参数

/**
 * @date 2020/7/27 14:51
 * 消费型接口  -> 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);
            }
        };

//        lambda 表达式 简写
        Consumer<String > consumer1 = (s)->{ System.out.println(s); };
        consumer1.accept("ss");
        consumer.accept("sout");
    }

}

6.4 Supplier -> 供给型接口

没有参数只有返回值。

/**
 * @date 2020/7/27 14:51
 * 供给型接口 -> Supplier
 * 没有参数只有返回值。
 */
public class Demo04 {
    public static void main(String[] args) {
        Supplier<String > stringSupplier = new Supplier<String>() {
            @Override
            public String get() {
                System.out.println("get");
                return "fas";
            }
        };

//        lambda 简写
        Supplier<String > supplier = ()->{return "fasfasgas";};
        supplier.get();
        stringSupplier.get();
    }
}

7. Steam流式计算

菜鸟教程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值