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

相关文章
|
1天前
|
安全 Java 大数据
Java性能优化(七)-多线程调优-并发容器的使用
Java性能优化(七)-多线程调优-并发容器的使用
13 0
|
1天前
|
存储 并行计算 Java
Java8中JUC包同步工具类深度解析(Semaphore,CountDownLatch,CyclicBarrier,Phaser)
Java8中JUC包同步工具类深度解析(Semaphore,CountDownLatch,CyclicBarrier,Phaser)
8 2
|
4天前
|
网络安全 安全 Java
Java一分钟之-SSL/TLS:安全套接字层与传输层安全
【6月更文挑战第2天】本文介绍了SSL/TLS协议在保护数据传输中的作用,以及Java中使用JSSE实现SSL/TLS的基础。内容涵盖SSL/TLS工作流程、版本、常见问题及解决办法。通过`SSLSocket`和`SSLServerSocket`示例展示了服务器和客户端的实现,并强调证书管理、配置检查和依赖更新的最佳实践,以确保安全的通信。
27 4
|
5天前
|
缓存 安全 Java
【Java面试——并发基础、并发关键字】
随着硬件指令集的发展,我们可以使用基于冲突检测的乐观并发策略: 先进行操作,如果没有其它线程争用共享数据,那操作就成功了,否则采取补偿措施(不断地重试,直到成功为止)。这种乐观的并发策略的许多实现都不需要将线程阻塞,因此这种同步操作称为非阻塞同步。 乐观锁需要操作和冲突检测这两个步骤具备原子性,这里就不能再使用互斥同步来保证了,只能靠硬件来完成。硬件支持的原子性操作最典型的是: 比较并交换(Compare-and-Swap,CAS)。CAS 指令需要有 3 个操作数,分别是内存地址 V、旧的预期值 A 和新值 B。当执行操作时,只有当 V 的值等于 A,才将 V 的值更新为 B。
|
6天前
|
JavaScript Java 测试技术
Java项目基于ssm+vue.js的农产品质量安全检测网站附带文章和源代码设计说明文档ppt
Java项目基于ssm+vue.js的农产品质量安全检测网站附带文章和源代码设计说明文档ppt
10 0
|
6天前
|
缓存 安全 Java
Java的线程池与并发工具类技术性文章
Java的线程池与并发工具类技术性文章
10 0
|
6天前
|
监控 Java 编译器
Java的内存模型与并发控制技术性文章
Java的内存模型与并发控制技术性文章
14 2
|
6天前
|
安全 Java 程序员
Java的迭代器与并发集合的技术性文章
Java的迭代器与并发集合的技术性文章
5 0
|
数据采集 Java 大数据
java高并发系列 - 第14天:JUC中的LockSupport工具类,必备技能
java高并发系列 - 第14天:JUC中的LockSupport工具类,必备技能这是java高并发系列第14篇文章。 本文主要内容: 讲解3种让线程等待和唤醒的方法,每种方法配合具体的示例介绍LockSupport主要用法对比3种方式,了解他们之间的区别LockSupport位于java.util.concurrent(简称juc)包中,算是juc中一个基础类,juc中很多地方都会使用LockSupport,非常重要,希望大家一定要掌握。
1220 0
|
1天前
|
监控 算法 Java
Java性能优化(九)-多线程调优-垃圾回收机制优化
Java性能优化(九)-多线程调优-垃圾回收机制优化
10 0