Java并发JUC(java.util.concurrent)Volatile\单例模式\CAS\原子引用

简介: Java并发JUC(java.util.concurrent)Volatile\单例模式\CAS\原子引用

在这里插入图片描述

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

@[TOC]

Volatile

  • 保证可见性

    package icu.lookyousmileface.volatilecode;
    
    import java.util.concurrent.Executors;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @author starrysky
     * @title: VolatileUse
     * @projectName Juc_Pro
     * @description: volatile原子性测试
     * @date 2021/1/307:52 上午
     */
    public class VolatileShow {
        /**
         * // 不加 volatile 程序就会死循环!
         * // 加 volatile 可以保证可见性
         */
        private  volatile static int num = 0;
    
        public static void main(String[] args) {
    
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                    5,
                    Runtime.getRuntime().availableProcessors(),
                    5,
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(3),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.DiscardOldestPolicy()
            );
            //线程1对内存中num=1的变化不知道
            threadPoolExecutor.execute(() -> {
                while (num == 0) {
    
                }
            });
    
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            num = 1;
    
            System.out.println("num:"+num);
    
            threadPoolExecutor.shutdown();
    
        }
    }
  • 不保证原子性

    原子性 : 不可分割

    线程A在执行任务的时候,不能被打扰的,也不能被分割。要么同时成功,要么同时失败。

    /**
     * @author starrysky
     * @title: VolatileNotAtomic
     * @projectName Juc_Pro
     * @description: Volatile不保证原子性
     * @date 2021/1/3011:32 上午
     */
    public class VolatileNotAtomic {
    
        private volatile static int num = 0;
    
        public  static void add(){
            num++;
        }
    
        public static void main(String[] args) {
    
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                    5,
                    Runtime.getRuntime().availableProcessors(),
                    5,
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(3),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.CallerRunsPolicy()
            );
    
            try {
                for (int i = 1; i <= 20; i++) {
                    threadPoolExecutor.execute(() -> {
                        for (int j = 1; j <= 1000; j++) {
                            add();
                        }
                    });
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                threadPoolExecutor.shutdown();
            }
            Thread.currentThread().getThreadGroup().list();
    
            System.out.println("sum:" + num);
    
        }
    }
    • 为了保证原子性,不实用sync、lock,可以使用atomic包下的原子类

      /**
       * @author starrysky
       * @title: AtomicUse
       * @projectName Juc_Pro
       * @description: 原子类使用
       * @date 2021/1/3011:51 上午
       */
      public class AtomicUse {
      
          private volatile static AtomicInteger number = new AtomicInteger();
      
          public static void add(){
              number.getAndIncrement();
          }
      
          public static void main(String[] args) {
      
              ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                      5,
                      Runtime.getRuntime().availableProcessors(),
                      5,
                      TimeUnit.SECONDS,
                      new LinkedBlockingQueue<>(3),
                      Executors.defaultThreadFactory(),
                      new ThreadPoolExecutor.CallerRunsPolicy()
      
              );
      
              try {
                  for (int i = 1; i <= 20; i++) {
                      threadPoolExecutor.execute(()->{
                          for (int j = 1; j <= 1000; j++) {
                              add();
                          }
                      });
                  }
      
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  threadPoolExecutor.shutdown();
              }
              /**
               * 让出主线程的CPU时间片,让其他线程使用
               */
              while (Thread.activeCount()>2){
                  System.out.println(Thread.currentThread().getName());
                  Thread.yield();
              }
              System.out.println("result:"+number);
          }
      }
  • 禁止指令重排

    什么是 指令重排:你写的程序,计算机并不是按照你写的那样去执行的。

    源代码-->编译器优化的重排--> 指令并行也可能会重排--> 内存系统也会重排---> 执行

    处理器在进行指令重排的时候,考虑:数据之间的依赖性!

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oVkWRf6K-1644224594265)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/acc5d510-aa44-4c78-bcba-854975117af7/Untitled.png)]

单例模式

  • 饿汉 单例模式

    /**
     * @author starrysky
     * @title: Hungry
     * @projectName Juc_Pro
     * @description: 饿汉 单例模式
     * @date 2021/1/304:47 下午
     */
    public class Hungry {
        private Hungry(){
    
        }
        private final static Hungry HUNGRY = new Hungry();
    
        public static Hungry getInstance(){
            return HUNGRY;
        }
    }
  • 懒汉 单例模式

    /**
     * @author starrysky
     * @title: LazyMan
     * @projectName Juc_Pro
     * @description: 懒汉单例模式
     * @date 2021/1/304:52 下午
     */
    public class LazyMan {
    
        private  volatile static LazyMan lazyMan;
        private static boolean lockSkey = false;
    
        private LazyMan() {
            synchronized (LazyMan.class){
                if (lockSkey == false){
                    lockSkey = true;
                }else {
                    throw new RuntimeException("不要妄图使用反射破坏!");
                }
            }
        }
        // 双重检测锁模式的 懒汉式单例 DCL懒汉式
        public static LazyMan getInstance() {
            if (lazyMan == null) {
                synchronized (LazyMan.class){
                    if (lazyMan==null){
                        lazyMan = new LazyMan();
                    }
                }
            }
            return lazyMan;
        }
    
    }
  • 静态内部类

    /**
     * @author starrysky
     * @title: StaticClass
     * @projectName Juc_Pro
     * @description: 静态内部类
     * @date 2021/1/307:11 下午
     */
    public class StaticClass {
    
        private StaticClass(){
    
        }
        private static class InnerClass{
            private static final Holder HOLDER = new Holder();
        }
    
        private static Holder getInstenac(){
           return InnerClass.HOLDER;
        }
    }

CAS

  • 修内功,操作系统,计算机网络原理。
  • 原子类

    /**
     * @author starrysky
     * @title: CasUse
     * @projectName Juc_Pro
     * @description: Cas
     * @date 2021/1/307:54 下午
     */
    public class CasUse {
        public static void main(String[] args) {
            AtomicInteger atomicInteger = new AtomicInteger(12);
                    //期望值,更新值
            System.out.println(atomicInteger.compareAndSet(12, 66));
            System.out.println(atomicInteger.get());
            System.out.println(atomicInteger.compareAndSet(66, 99));
            System.out.println(atomicInteger.get());
            
        }
    }
  • Unsafe类

    import java.util.function.IntUnaryOperator;
    import java.util.function.IntBinaryOperator;
    import sun.misc.Unsafe;
    
    /**
     * An {@code int} value that may be updated atomically.  See the
     * {@link java.util.concurrent.atomic} package specification for
     * description of the properties of atomic variables. An
     * {@code AtomicInteger} is used in applications such as atomically
     * incremented counters, and cannot be used as a replacement for an
     * {@link java.lang.Integer}. However, this class does extend
     * {@code Number} to allow uniform access by tools and utilities that
     * deal with numerically-based classes.
     *
     * @since 1.5
     * @author Doug Lea
    */
    public class AtomicInteger extends Number implements java.io.Serializable {
        private static final long serialVersionUID = 6214790243416807050L;
    
        // setup to use Unsafe.compareAndSwapInt for updates
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        private static final long valueOffset;
    
        static {
            try {
                valueOffset = unsafe.objectFieldOffset
                    (AtomicInteger.class.getDeclaredField("value"));
            } catch (Exception ex) { throw new Error(ex); }
        }
    • ⚠️ Java无法操作内存,c++可以,Java操作C++,C++再操作内存
    public final int getAndAddInt(Object o, long offset, int delta) {
            int v;
            do {
                    //内存中的值
                v = getIntVolatile(o, offset);
                    //自旋锁,CAS : 比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作!如果不是就一直循环!
            } while (!compareAndSwapInt(o, offset, v, v + delta));
            return v;
        }
    • 缺点:

      1、 循环会耗时

      2、一次性只能保证一个共享变量的原子性

      3、ABA问题

  • ABA问题(立马换太子)

    /**
     * @author starrysky
     * @title: CasABAProblem
     * @projectName Juc_Pro
     * @description: ABA问题, 立马换太子问题
     * @date 2021/1/308:03 下午
     */
    public class CasABAProblem {
        public static void main(String[] args) {
            AtomicInteger atomicInteger = new AtomicInteger(20);
    
            //====================捣乱换太子=============
            atomicInteger.compareAndSet(20,66);
            atomicInteger.compareAndSet(66,20);
            //==================== 不知情的线程===========
            atomicInteger.compareAndSet(20,99);
            System.out.println(atomicInteger.get());
        }
    }

原子引用

  • 解决ABA 问题,引入原子引用! 对应的思想:乐观锁!
  • 带版本号 的原子操作!
  • 试验代码

    package icu.lookyousmileface.cas;
    
    import java.util.concurrent.Executors;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicStampedReference;
    
    /**
     * @author starrysky
     * @title: ReferenceUse
     * @projectName Juc_Pro
     * @description: AtomicStampedReference
     * @date 2021/1/308:17 下午
     */
    public class ReferenceUse {
        public static void main(String[] args) {
            AtomicStampedReference<Integer> atomicRefe = new AtomicStampedReference<>(1, 1);
    
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                    5,
                    Runtime.getRuntime().availableProcessors(),
                    5,
                    TimeUnit.SECONDS,
                    new LinkedBlockingQueue<>(3),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.CallerRunsPolicy()
            );
    
            try {
                threadPoolExecutor.execute(()->{
                    int stamp = atomicRefe.getStamp();
                    System.out.println(Thread.currentThread().getName()+"=>"+stamp);
    
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    atomicRefe.compareAndSet(1,2,atomicRefe.getStamp(),atomicRefe.getStamp()+1);
                    System.out.println(Thread.currentThread().getName()+"=>"+atomicRefe.getStamp());
    
                    System.out.println(atomicRefe.compareAndSet(2, 1, atomicRefe.getStamp(), atomicRefe.getStamp() + 1));
                    System.out.println(Thread.currentThread().getName()+"=>"+atomicRefe.getStamp());
                });
                /**
                 * 和乐观锁的原理一样
                 */
                threadPoolExecutor.execute(()->{
                    int stamp = atomicRefe.getStamp();
                    System.out.println(Thread.currentThread().getName()+"=>"+stamp);
    
                    try {
                        TimeUnit.SECONDS.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    System.out.println(atomicRefe.compareAndSet(1, 2, stamp, stamp + 1));
    
                    System.out.println(Thread.currentThread().getName()+"=>"+atomicRefe.getStamp());
                });
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            threadPoolExecutor.shutdown();
            }
        }
    }

    ⚠️ Tips:Integer 使用了对象缓存机制,默认范围是 -128 ~ 127 ,推荐使用静态工厂方法 valueOf 获取对象实例,而不是 new,因为 valueOf 使用缓存,而 new 一定会创建新的对象分配新的内存空间;

相关文章
|
14天前
|
设计模式 安全 Java
Java编程中的单例模式:理解与实践
【10月更文挑战第31天】在Java的世界里,单例模式是一种优雅的解决方案,它确保一个类只有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的实现方式、使用场景及其优缺点,同时提供代码示例以加深理解。无论你是Java新手还是有经验的开发者,掌握单例模式都将是你技能库中的宝贵财富。
19 2
|
24天前
|
设计模式 安全 Java
Java编程中的单例模式深入剖析
【10月更文挑战第21天】在Java的世界里,单例模式是设计模式中一个常见而又强大的存在。它确保了一个类只有一个实例,并提供一个全局访问点。本文将深入探讨如何正确实现单例模式,包括常见的实现方式、优缺点分析以及最佳实践,同时也会通过实际代码示例来加深理解。无论你是Java新手还是资深开发者,这篇文章都将为你提供宝贵的见解和技巧。
92 65
|
14天前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
|
14天前
|
设计模式 安全 Java
Java编程中的单例模式深入解析
【10月更文挑战第31天】在编程世界中,设计模式就像是建筑中的蓝图,它们定义了解决常见问题的最佳实践。本文将通过浅显易懂的语言带你深入了解Java中广泛应用的单例模式,并展示如何实现它。
|
19天前
|
Java 数据库连接 数据库
如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面
本文介绍了如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面。通过合理配置初始连接数、最大连接数和空闲连接超时时间,确保系统性能和稳定性。文章还探讨了同步阻塞、异步回调和信号量等并发控制策略,并提供了异常处理的最佳实践。最后,给出了一个简单的连接池示例代码,并推荐使用成熟的连接池框架(如HikariCP、C3P0)以简化开发。
40 2
|
21天前
|
设计模式 SQL 安全
Java编程中的单例模式深入解析
【10月更文挑战第24天】在软件工程中,单例模式是设计模式的一种,它确保一个类只有一个实例,并提供一个全局访问点。本文将探讨如何在Java中使用单例模式,并分析其优缺点以及适用场景。
11 0
|
25天前
|
SQL 缓存 安全
[Java]volatile关键字
本文介绍了Java中volatile关键字的原理与应用,涵盖JMM规范、并发编程的三大特性(可见性、原子性、有序性),并通过示例详细解析了volatile如何实现可见性和有序性,以及如何结合synchronized、Lock和AtomicInteger确保原子性,最后讨论了volatile在单例模式中的经典应用。
31 0
|
25天前
|
SQL 设计模式 Java
[Java]单例模式
本文介绍了单例模式的概念及其实现方式,包括饿汉式和懒汉式两种形式,并详细探讨了懒汉式中可能出现的线程安全问题及其解决方案,如锁方法、锁代码块和双重检查锁(DCL)。文章通过示例代码帮助读者更好地理解和应用单例模式。
28 0
|
3月前
|
安全 Java 调度
解锁Java并发编程高阶技能:深入剖析无锁CAS机制、揭秘魔法类Unsafe、精通原子包Atomic,打造高效并发应用
【8月更文挑战第4天】在Java并发编程中,无锁编程以高性能和低延迟应对高并发挑战。核心在于无锁CAS(Compare-And-Swap)机制,它基于硬件支持,确保原子性更新;Unsafe类提供底层内存操作,实现CAS;原子包java.util.concurrent.atomic封装了CAS操作,简化并发编程。通过`AtomicInteger`示例,展现了线程安全的自增操作,突显了这些技术在构建高效并发程序中的关键作用。
69 1
|
2月前
|
Java API 容器
JAVA并发编程系列(10)Condition条件队列-并发协作者
本文通过一线大厂面试真题,模拟消费者-生产者的场景,通过简洁的代码演示,帮助读者快速理解并复用。文章还详细解释了Condition与Object.wait()、notify()的区别,并探讨了Condition的核心原理及其实现机制。