Java并发JUC(java.util.concurrent)集合不安全

简介: Java并发JUC(java.util.concurrent)集合不安全

在这里插入图片描述

👨🏻‍🎓博主介绍:大家好,我是芝士味的椒盐,一名在校大学生,热爱分享知识,很高兴在这里认识大家🌟
🌈擅长领域:Java、大数据、运维、电子
🙏🏻如果本文章各位小伙伴们有帮助的话,🍭关注+👍🏻点赞+🗣评论+📦收藏,相应的有空了我也会回访,互助!!!
🤝另本人水平有限,旨在创作简单易懂的文章,在文章描述时如有错,恳请各位大佬指正,在此感谢!!!

@[TOC]

集合是不安全的

  • 先给大家上个集合框架家族图

在这里插入图片描述

  • List不安全

    package icu.lookyousmileface.notsafe;
    
    import java.util.*;
    import java.util.concurrent.CopyOnWriteArrayList;
    
    /**
     * @author starrysky
     * @title: UnSafeList
     * @projectName Juc_Pro
     * @description: 集合不安全
     * @date 2021/1/2912:04 下午
     */
    public class UnSafeList {
        public static void main(String[] args) {
            // 并发下 ArrayList 不安全的吗,Synchronized;
            /**
             * 解决方案;
             * 1、List<String> list = new Vector<>();
             * 2、List<String> list = Collections.synchronizedList(new ArrayList<>());
             * 3、List<String> list = new CopyOnWriteArrayList<>();
             */
            // CopyOnWrite 写入时复制  COW  计算机程序设计领域的一种优化策略;
            // 多个线程调用的时候,list,读取的时候,固定的,写入(覆盖)
            // 在写入的时候避免覆盖,造成数据问题!
            // 读写分离
            // CopyOnWriteArrayList  比 Vector Nb 在哪里?
    //        List<String> list = new Vector<>();
            List<String> list = new CopyOnWriteArrayList();
    //        List<String> list = Collections.synchronizedList(new ArrayList<>());
    //        List<String> list = new ArrayList<>();
            for (int i = 0; i < 100; i++) {
                new Thread(()->{
                    list.add(UUID.randomUUID().toString().substring(0,5));
                    System.out.println(list);
                },String.valueOf(i)).start();
            }
    
        }
    }
  • Set不安全

    package icu.lookyousmileface.notsafe;
    
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.Set;
    import java.util.UUID;
    import java.util.concurrent.CopyOnWriteArraySet;
    
    /**
     * @author starrysky
     * @title: UnSafeSet
     * @projectName Juc_Pro
     * @description: Set不安全,set底层底层HashMap
     * @date 2021/1/291:00 下午
     */
    public class UnSafeSet {
        public static void main(String[] args) {
            /**
             * 和List同理
             */
    //        Set<String> set = new HashSet<>();
    //        Set<String> set =  Collections.synchronizedSet(new HashSet<>());
            Set<String> set = new CopyOnWriteArraySet<>();
            for (int i = 0; i < 30; i++) {
                new Thread(() -> {
                    set.add(UUID.randomUUID().toString().substring(0, 6));
                    System.out.println(set);
    
                }, String.valueOf(i)).start();
            }
        }
    }

    ⚠️ Tips:

    HashSet底层:底层使用hashmap去重,vlue是常量值,key就是我们传进去的值

    public HashSet() {
            map = new HashMap<>();
        }
    
    public boolean add(E e) {
            return map.put(e, PRESENT)==null;
        }
    
    private static final Object PRESENT = new Object();
  • Map不安全

    package icu.lookyousmileface.notsafe;
    
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.UUID;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * @author starrysky
     * @title: UnSafeMap
     * @projectName Juc_Pro
     * @description: Map不安全
     * @date 2021/1/291:14 下午
     */
    public class UnSafeMap {
        public static void main(String[] args) {
            // map 是这样用的吗? 不是,工作中不用 HashMap
            // 默认等价于什么?  new HashMap<>(16,0.75);
    //        Map<String,String> map = new HashMap<>();
    //        Map<String,String> map = Collections.synchronizedMap(new HashMap<>());
            Map<String,String> map =  new ConcurrentHashMap<>();
            for (int i = 0; i < 30; i++) {
                new Thread(()->{
                    map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
                    System.out.println(map);
                },String.valueOf(i)).start();
            }
        }
    }

    ⚠️ Tips:new HashMap<>();默认等价于new HashMap<>(16,0.75);,工作中不用 HashMap

Callable

在这里插入图片描述
在这里插入图片描述

  • 代码实现:

    package icu.lookyousmileface.callable;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    /**
     * @author starrysky
     * @title: CallableUse
     * @projectName Juc_Pro
     * @description: Callable代替了Runable接口,run/call,有异常有返回值
     * @date 2021/1/291:43 下午
     */
    public class CallableUse {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            //适配类
            FutureTask<Integer> integerFutureTask = new FutureTask<>(new MyThread());
            new Thread(integerFutureTask,"A").start();
            new Thread(integerFutureTask,"B").start();//有缓存,效率高
            //有返回值,get会产生阻塞,可以使用异步线程通信长处理
            System.out.println(integerFutureTask.get());
        }
    }
    
    class MyThread implements Callable<Integer> {
    
        @Override
        public Integer call() throws Exception {
            System.out.println("调用了call方法");
            return 1024;
        }
    }

    ⚠️ Tips:

    1、可以有返回值

    2、可以抛出异常

    3、方法不同,run()/ call()

    细节:

    1、有缓存

    2、结果可能需要等待,会阻塞!

常用辅助类(必会)

  • CountDownLatch

    package icu.lookyousmileface.concurrentutils;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.FutureTask;
    
    /**
     * @author starrysky
     * @title: CountDownLatchUse
     * @projectName Juc_Pro
     * @description: CountDownLatch辅助类常用必会
     * @date 2021/1/292:13 下午
     */
    public class CountDownLatchUse {
        public static void main(String[] args) {
            CountDownLatch countDownLatch = new CountDownLatch(6);
    
            for (int i = 1; i <=6; i++) {
                new Thread(new FutureTask<Integer>(()-> {
                    System.out.println(Thread.currentThread().getName()+":"+"走出教室!");
                    countDownLatch.countDown();
                    return 1024;}),String.valueOf(i)).start();
            }
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("全员已经都离开来教室,教室大门锁上!!!");
        }
    }

    ⚠️ 原理:countDownLatch.countDown(); // 数量-1,countDownLatch.await(); // 等待计数器归零,然后再向下执行,每次有线程调用 countDown() 数量-1,假设计数器变为0,countDownLatch.await() 就会被唤醒,继续执行!

  • CyclicBarrier

    package icu.lookyousmileface.concurrentutils;
    
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;
    
    /**
     * @author starrysky
     * @title: CyclicBarrierUse
     * @projectName Juc_Pro
     * @description: 加法计数器
     * @date 2021/1/292:28 下午
     */
    public class CyclicBarrierUse {
        public static void main(String[] args) {
    //CyclicBarrier本身就可以自带一个线程
            CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
                System.out.println("召唤神龙!");
            });
    
            for (int i = 1; i <= 7; i++) {
                final int temp = i;
                new Thread(()->{
                    System.out.println(Thread.currentThread().getName()+":收集齐"+temp+"颗龙珠");
                    try {
                        //此处的await是等待达到parties计数的时候,执行cyclicBarrier的线程,没有将不会执行
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                },String.valueOf(i)).start();
            }
        }
    }
  • Semaphore

    • 信号量,也就是限流的作用,比较常用
    package icu.lookyousmileface.concurrentutils;
    
    import java.util.concurrent.Semaphore;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @author starrysky
     * @title: SemaphoreUse
     * @projectName Juc_Pro
     * @description:
     * @date 2021/1/292:38 下午
     */
    public class SemaphoreUse {
        public static void main(String[] args) {
            //可以用来限制流量
            Semaphore semaphore = new Semaphore(3);
    
            for (int i = 1; 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();
                    }
                },String.valueOf(i)).start();
            }
        }
    }

    ⚠️ Tips:

    原理:

    semaphore.acquire() 获得,假设如果已经满了,等待,等待被释放为止!semaphore.release(); 释放,会将当前的信号量释放 + 1,然后唤醒等待的线程!

    作用: 多个共享资源互斥的使用!并发限流,控制最大的线程数!

读写锁

  • 试验代码:

    package icu.lookyousmileface.readeandwritelock;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    /**
     * @author starrysky
     * @title: ReadAndWriteLockUse
     * @projectName Juc_Pro
     * @description:  读写锁
     * 独占锁(写锁) 一次只能被一个线程占有
     * 共享锁(读锁) 多个线程可以同时占有
     * ReadWriteLock
     * 读-读  可以共存!
     * 读-写  不能共存!
     * 写-写  不能共存!
     * @date 2021/1/293:08 下午
     */
    public class ReadAndWriteLockUse {
        public static void main(String[] args) {
            MyCache myCache = new MyCache();
    
            for (int i = 1; i <= 6; i++) {
                final int  temp = i;
                new Thread(()->{
                    myCache.put(String.valueOf(temp),String.valueOf(temp));
                },String.valueOf(i)).start();
            }
    
            for (int i = 1; i <= 6; i++) {
                final int  temp = i;
                new Thread(()->{
                    myCache.get(String.valueOf(temp));
                },String.valueOf(i)).start();
            }
        }
    }
    
    class MyCache{
    
        private final Map<String,String> map = new HashMap<>(16, 0.75F);
        private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    
        // 存,写入的时候,只希望同时只有一个线程写
        public void put(String key,String value){
            reentrantReadWriteLock.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 {
                reentrantReadWriteLock.writeLock().unlock();
            }
        }
        // 取,读,所有人都可以读!
        public void get(String key){
            reentrantReadWriteLock.readLock().lock();
            try{
                System.out.println(Thread.currentThread().getName()+":正在读取"+key);
                String value = map.get(key);
                System.out.println(Thread.currentThread().getName()+":"+key+"读取完成!"+"值:"+value);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                reentrantReadWriteLock.readLock().unlock();
            }
        }
    }

阻塞队列

在这里插入图片描述

  • 阻塞队列:
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

⚠️ Tips:会使用 阻塞队列的地方:多线程并发处理,线程池!

四组API

在这里插入图片描述

SynchronousQueue 同步队列

  • 试验代码:

    package icu.lookyousmileface.syncqueue;
    
    import java.util.concurrent.SynchronousQueue;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @author starrysky
     * @title: SyncQueueUse
     * @projectName Juc_Pro
     * @description: 同步队列
     * @date 2021/1/299:17 下午
     */
    public class SyncQueueUse {
        public static void main(String[] args) throws InterruptedException {
            SynchronousQueue<String> syncQueue = new SynchronousQueue<>();
    
            //无须for循环会自动产生一种互喂模式
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + ":" + "A入队列");
                    syncQueue.put("A");
    
                    System.out.println(Thread.currentThread().getName() + ":" + "B入队列");
                    syncQueue.put("B");
    
                    System.out.println(Thread.currentThread().getName() + ":" + "C入队列");
                    syncQueue.put("C");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "T1").start();
    
            new Thread(() -> {
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println(Thread.currentThread().getName() + ":" + syncQueue.take() + "出队列");
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println(Thread.currentThread().getName() + ":" + syncQueue.take() + "出队列");
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println(Thread.currentThread().getName() + ":" + syncQueue.take() + "出队列");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "T2").start();
    
        }
    }

    ⚠️ Tips:

    没有容量,进去一个元素,必须等待取出来之后,才能再往里面放一个元素!put、take

相关文章
|
3天前
|
安全 Java API
JAVA并发编程JUC包之CAS原理
在JDK 1.5之后,Java API引入了`java.util.concurrent`包(简称JUC包),提供了多种并发工具类,如原子类`AtomicXX`、线程池`Executors`、信号量`Semaphore`、阻塞队列等。这些工具类简化了并发编程的复杂度。原子类`Atomic`尤其重要,它提供了线程安全的变量更新方法,支持整型、长整型、布尔型、数组及对象属性的原子修改。结合`volatile`关键字,可以实现多线程环境下共享变量的安全修改。
|
7天前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
7天前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
18天前
|
监控 Java 调度
【Java学习】多线程&JUC万字超详解
本文详细介绍了多线程的概念和三种实现方式,还有一些常见的成员方法,CPU的调动方式,多线程的生命周期,还有线程安全问题,锁和死锁的概念,以及等待唤醒机制,阻塞队列,多线程的六种状态,线程池等
79 6
【Java学习】多线程&JUC万字超详解
|
14天前
|
安全 Java API
【性能与安全的双重飞跃】JDK 22外部函数与内存API:JNI的继任者,引领Java新潮流!
【9月更文挑战第7天】JDK 22外部函数与内存API的发布,标志着Java在性能与安全性方面实现了双重飞跃。作为JNI的继任者,这一新特性不仅简化了Java与本地代码的交互过程,还提升了程序的性能和安全性。我们有理由相信,在外部函数与内存API的引领下,Java将开启一个全新的编程时代,为开发者们带来更加高效、更加安全的编程体验。让我们共同期待Java在未来的辉煌成就!
43 11
|
15天前
|
安全 Java API
【本地与Java无缝对接】JDK 22外部函数和内存API:JNI终结者,性能与安全双提升!
【9月更文挑战第6天】JDK 22的外部函数和内存API无疑是Java编程语言发展史上的一个重要里程碑。它不仅解决了JNI的诸多局限和挑战,还为Java与本地代码的互操作提供了更加高效、安全和简洁的解决方案。随着FFM API的逐渐成熟和完善,我们有理由相信,Java将在更多领域展现出其强大的生命力和竞争力。让我们共同期待Java编程新纪元的到来!
38 11
|
22天前
|
Java
用JAVA架建List集合为树形结构的代码方法
这段代码定义了一个表示树形结构的 `Node` 类和一个用于构建树形结构的 `TreeController`。`Node` 类包含基本属性如 `id`、`pid`、`name` 和 `type`,以及子节点列表 `children`。`TreeController` 包含初始化节点列表并将其转换为树形结构的方法。通过过滤和分组操作实现树形结构的构建。详情可见:[代码示例链接1](http://www.zidongmutanji.com/zsjx/43551.html),[代码效果参考链接2](https://www.257342.com/sitemap/post.html)。
28 5
|
22天前
|
存储 Java 程序员
Java中的集合框架:从入门到精通
【8月更文挑战第30天】在Java的世界里,集合框架是一块基石,它不仅承载着数据的存储和操作,还体现了面向对象编程的精髓。本篇文章将带你遨游Java集合框架的海洋,从基础概念到高级应用,一步步揭示它的奥秘。你将学会如何选择合适的集合类型,掌握集合的遍历技巧,以及理解集合框架背后的设计哲学。让我们一起探索这个强大工具,解锁数据结构的新视角。
|
20天前
|
前端开发 开发者 安全
JSF支付功能大揭秘:探索如何在Java世界中实现安全无缝的在线支付体验
【8月更文挑战第31天】在电子商务和在线交易日益普及的今天,实现在线支付功能已成为许多Web应用的必备需求。JavaServer Faces (JSF) 作为一种流行的Java Web框架,提供了丰富的组件和工具来构建用户界面,包括与支付网关集成以实现在线支付。支付网关是处理信用卡和借记卡支付的系统,在商家和银行之间起到桥梁作用。本文将探讨如何使用JSF与支付网关集成,以及实现在线支付功能时需要考虑的关键点
32 0
|
21天前
|
存储 算法 Java
Java中的集合框架深度解析与实践
【8月更文挑战第31天】在Java编程的海洋中,集合框架扮演着不可或缺的角色。本文将带你领略Java集合框架的魅力,从理论到实践,深入浅出地探索List、Set和Map等核心接口的使用技巧。我们将通过具体代码示例,展示如何在日常开发中高效运用这些工具,让你的代码更加优雅和高效。无论你是初学者还是有经验的开发者,这篇文章都将为你打开一扇通往Java集合世界的大门。