栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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;


public class VolatileShow {
    
    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在执行任务的时候,不能被打扰的,也不能被分割。要么同时成功,要么同时失败。

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包下的原子类

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();
        }
        
        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)]

单例模式

饿汉 单例模式

public class Hungry {
    private Hungry(){

    }
    private final static Hungry HUNGRY = new Hungry();

    public static Hungry getInstance(){
        return HUNGRY;
    }
}

懒汉 单例模式

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;
    }

}

静态内部类

public class StaticClass {

    private StaticClass(){

    }
    private static class InnerClass{
        private static final Holder HOLDER = new Holder();
    }

    private static Holder getInstenac(){
       return InnerClass.HOLDER;
    }
}
CAS

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

原子类

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;


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问题(立马换太子)

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;


public class ReferenceUse {
    public static void main(String[] args) {
        AtomicStampedReference 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 一定会创建新的对象分配新的内存空间;

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/732259.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号