• Java进阶——多线程相关,实际应用中的积累,持续更新


    在这里插入图片描述


    多线程相关

    CountDownLatch

    案例:主线程的执行需要等待子线程执行完,等各个线程执行完毕后,主线程做收尾的工作

    • 初始化一个:final CountDownLatch latch = new CountDownLatch(3);
    • 线程池中的子线程调用 countDown方法进行减1;
    • 主线程启动后,等待子线程不断减1,直到为0后,主线程继续往下执行;
    package com.tianju.myTest;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class CountdownLatchTest1 {
    
        public static void main(String[] args) {
            ExecutorService service = Executors.newFixedThreadPool(3);
            final CountDownLatch latch = new CountDownLatch(3);
            for (int i = 0; i < 3; i++) {
                Runnable runnable = new Runnable() {
    
                    @Override
                    public void run() {
                        try {
                            System. out.println("子线程" + Thread.currentThread().getName() + "开始执行");
                            Thread. sleep((long) (Math. random() * 10000));
                            System. out.println("子线程" + Thread.currentThread().getName() + "执行完成");
                            latch.countDown(); // 当前线程调用此方法,则计数减一
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
                service.execute(runnable);
            }
    
            try {
                System. out.println("主线程" + Thread.currentThread().getName() + "等待子线程执行完成..." );
                latch.await(); // 阻塞当前线程,直到计时器的值为0
                System. out.println("主线程" + Thread.currentThread().getName() + "开始执行...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                service.shutdown();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    赛跑的案例

    案例2:4名选手参加赛跑,选手需要等待裁判发送指令;裁判发送完指令后,需要等所有选手到达终点;所有选手到达终点后,裁判汇总成绩。

    • 主线程:裁判发指令,裁判等选手到达终点,到达终点后,汇总成绩;
    • 子线程:每个选手需要阻塞在裁判发指令之前,主线程发指令后,子线程继续运行;此时主线程阻塞,所有子线程结束后,主线程继续运行

    实现的思路

    • 定义两个CountDownLatch,一个为1,一个为4;
    • CountDownLatch(1),用来控制等待裁判指令,主线程先休眠,让出资源,让子线程获得cpu资源,子线程通过await 阻塞;
    • 主线程休眠结束后,对1进行-1,然后await 4 阻塞,触发子线程,子线程继续运行;
    • 子线程在运行过程中对于4 进行-1,等到值为0时,触发主线程的await 4 阻塞;
    • 主线程继续运行,裁判进行成绩的汇总

    在这里插入图片描述

    在这里插入图片描述

    package com.tianju.myTest;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    // https://www.cnblogs.com/tstd/p/4987935.html
    public class CountdownLatchTest2 {
    
        public static void main(String[] args) {
            ExecutorService service = Executors.newCachedThreadPool();
            final CountDownLatch cdOrder = new CountDownLatch(1);
            final CountDownLatch cdAnswer = new CountDownLatch(4);
            for (int i = 0; i < 4; i++) {
                Runnable runnable = new Runnable() {
                    public void run() {
                        try {
                            System.out.println("选手" + Thread.currentThread().getName() + "正等待裁判发布口令");
                            cdOrder.await(); // 线程都阻塞在这里等待释放
                            System.out.println("选手" + Thread.currentThread().getName() + "已接受裁判口令");
                            Thread.sleep((long) (Math. random() * 10000));
                            System.out.println("选手" + Thread.currentThread().getName() + "到达终点");
                            cdAnswer.countDown(); // 进行-1操作,4个线程都在操作CountDownLatch
                            System.out.println("cdAnswer---->:"+cdAnswer);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                };
                service.execute(runnable);
            }
            try {
                Thread. sleep((long) (Math. random() * 10000));
    
                System. out.println("裁判" + Thread.currentThread ().getName() + "即将发布口令" );
                cdOrder.countDown();
                System. out.println("裁判" + Thread.currentThread ().getName() + "已发送口令,正在等待所有选手到达终点" );
                cdAnswer.await();
                System. out.println("所有选手都到达终点" );
                System. out.println("裁判" + Thread.currentThread ().getName() + "汇总成绩排名" );
            } catch (Exception e) {
                e.printStackTrace();
            }
            service.shutdown();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    countDownLatch.await(300, TimeUnit.SECONDS);

    await方法的对比

    • 没有设置时间,会一直阻塞,直到countdown为0;
    • 设置了时间,在超过这个时间后,解除阻塞,返回false;

    线程一直阻塞的情况

    在这里插入图片描述

    到达时间后,就解除阻塞,并返回false

    在这里插入图片描述

    -1成功,返回true

    在这里插入图片描述

    Java其他进阶

    Map的put方法

    • Map 的 put 方法其实是有返回值的

    在这里插入图片描述

    package com.tianju.myTest;
    
    import java.util.HashMap;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * hashMap 的 put 方法其实是有返回值的
     */
    public class ConHashMap {
        public static void main(String[] args) {
            ConcurrentHashMap<Object, Object> concurrentHashMap = new ConcurrentHashMap<>();
            // 如果有了键为 pet,还能往里面放
            concurrentHashMap.put("pet", 567);
            Object put = concurrentHashMap.put("pet", "task");
            System.out.println(put);
            if (put!=null){
                System.out.println("======== current key used! ========");
            }
            System.out.println(concurrentHashMap);
    
            HashMap<Object, Object> hashMap = new HashMap<>();
            hashMap.put("pet", 123);
            Object pet = hashMap.put("pet", 561);
            System.out.println(pet);
            System.out.println(hashMap);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    只放一个元素的集合

    • 基于内存或者业务的考虑,有时候集合只放一个元素,可以用collections下面的singleton集合

    在这里插入图片描述

    package com.tianju.myTest;
    
    import java.util.Collections;
    import java.util.List;
    
    /**
     * 只能存放一个元素的 List,不会造成内存空间的浪费
     */
    public class SingletonListTest {
        public static void main(String[] args) {
            String s = "hello, singleton";
            List<String> list = Collections.singletonList(s);
            list.add("second element");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    【LaTex】LaTex的下载与安装(超详细、超简洁)
    NVIDIA大力推动DPU“出圈”,搅动中国AI基础设施市场
    java计算机毕业设计航空订票系统源码+mysql数据库+系统+lw文档+部署(2)
    Yocto Beaglebone-Black 编译记录
    从数学0到指针NULL,到std vector右边界,到空操作
    【sklearn】fit()、transform()和fit_transform()的区别
    正则表达式简介和使用(Java)
    互联网、政务外网、政务专网、政务内网的区别
    C++学习——继承
    [附源码]java毕业设计西柚网购物系统
  • 原文地址:https://blog.csdn.net/Pireley/article/details/134563183