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 一定会创建新的对象分配新的内存空间;

相关文章
|
1天前
|
Java API 调度
[Java并发基础]多进程编程
[Java并发基础]多进程编程
|
6天前
|
安全 Java
深入理解 Java 多线程和并发工具类
【4月更文挑战第19天】本文探讨了Java多线程和并发工具类在实现高性能应用程序中的关键作用。通过继承`Thread`或实现`Runnable`创建线程,利用`Executors`管理线程池,以及使用`Semaphore`、`CountDownLatch`和`CyclicBarrier`进行线程同步。保证线程安全、实现线程协作和性能调优(如设置线程池大小、避免不必要同步)是重要环节。理解并恰当运用这些工具能提升程序效率和可靠性。
|
8天前
|
Java 开发者
Java中多线程并发控制的实现与优化
【4月更文挑战第17天】 在现代软件开发中,多线程编程已成为提升应用性能和响应能力的关键手段。特别是在Java语言中,由于其平台无关性和强大的运行时环境,多线程技术的应用尤为广泛。本文将深入探讨Java多线程的并发控制机制,包括基本的同步方法、死锁问题以及高级并发工具如java.util.concurrent包的使用。通过分析多线程环境下的竞态条件、资源争夺和线程协调问题,我们提出了一系列实现和优化策略,旨在帮助开发者构建更加健壮、高效的多线程应用。
7 0
|
8天前
|
存储 缓存 安全
Java并发基础之互斥同步、非阻塞同步、指令重排与volatile
在Java中,多线程编程常常涉及到共享数据的访问,这时候就需要考虑线程安全问题。Java提供了多种机制来实现线程安全,其中包括互斥同步(Mutex Synchronization)、非阻塞同步(Non-blocking Synchronization)、以及volatile关键字等。 互斥同步(Mutex Synchronization) 互斥同步是一种基本的同步手段,它要求在任何时刻,只有一个线程可以执行某个方法或某个代码块,其他线程必须等待。Java中的synchronized关键字就是实现互斥同步的常用手段。当一个线程进入一个synchronized方法或代码块时,它需要先获得锁,如果
24 0
|
17天前
|
存储 缓存 安全
【企业级理解】高效并发之Java内存模型
【企业级理解】高效并发之Java内存模型
|
24天前
|
安全 Java
Java中的多线程并发控制
在Java中,多线程是实现并发执行任务的一种重要方式。然而,随着多个线程同时访问共享资源,可能会导致数据不一致和其他并发问题。因此,了解并掌握Java中的多线程并发控制机制显得尤为重要。本文将深入探讨Java的多线程并发控制,包括synchronized关键字、Lock接口、Semaphore类以及CountDownLatch类等,并通过实例代码演示其使用方法和注意事项。
12 2
|
28天前
|
缓存 NoSQL Java
Java项目:支持并发的秒杀项目(基于Redis)
Java项目:支持并发的秒杀项目(基于Redis)
26 0
|
30天前
|
算法 安全 Java
Java中的并发编程:理解并发性能优化
在当今软件开发领域,多核处理器的普及使得并发编程变得更加重要。本文将深入探讨Java中的并发编程,介绍并发性能优化的关键技术,帮助开发人员更好地利用多核处理器提升应用程序性能。
|
1月前
|
安全 Java API
Java并发 - J.U.C并发容器类 list、set、queue
Queue API 阻塞是通过 condition 来实现的,可参考 Java 并发 - Lock 接口 ArrayBlockingQueue 阻塞 LinkedBlockingQueue 阻塞 ArrayQueue 非阻塞 LinkedQueue 非阻塞
|
3月前
|
安全 Java 编译器
Java并发编程学习6-同步容器类和并发容器
【1月更文挑战第6天】本篇介绍同步容器类和并发容器的相关内容(Vector、ConcurrentHashMap、CopyOnWriteArrayList)
34 3
Java并发编程学习6-同步容器类和并发容器