美文网首页多线程与高并发
2 volatile、Sync优化和CAS

2 volatile、Sync优化和CAS

作者: Mr_Editor | 来源:发表于2020-02-18 23:02 被阅读0次

目录

  1. volatile 特性
  2. Sync锁优化方式
  3. CAS 概念和使用

1 volatile特性

  • 1.1 保证变量的可见性

可见性:即变量的变化是否能够观察到;volatile 通过cpu的缓存一致性协议保证变量可见性
代码分析:
**在示代码中,当running == true,m()方法体中while执行条件为真,在测试方法中改变running的值,但是线程t1调用m()方法中的while条件依然为真,这是因为对于变量running,线程t1将running拷贝到自己的工作区,同时主线程也将running拷贝到自己的工作区,t1工作区中的running无法看到主线程方法区中对running的改动

  • 使用volatile修饰变量保证变量的可见性
public class VolatileClass {
    private /*volatile*/ boolean running = true;
    //测试可见性
    public static void test01() {
        VolatileClass vc = new VolatileClass();
        new Thread(vc::m, "t1").start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        vc.running = false;
    }
    public void m() {
        System.out.println("m start ");
        while (running) {
            //业务代码省略
        }
        System.out.println("m end");
    }
}
  • 1.2 禁止指令重排序

compiler在对代码进行编译时,对代码优化可能会改变代码顺序。
示例代码时Double Check Lock单例模式(双重检查单例模式)

  • 代码分析

双重检查单例模式instance是否需要volatile修饰?
需要! 当两个线程同时获取instance时,在第一次instance == null检查时可能会出现问题,指令重排序导致的问题!
JVM中new 对象时,指令分为三步:申请内存,变量初始化值(此时instatce已不为空),变量赋值给instance。
当t1 t2争用getInstance()时,如果t1执行到第二步,此时t2进行first check ,instance不为空,则t2得到未初始化完毕的instance。

public class DCL {
    private static /*volatile*/ DCL instance;//双重检查单例模式 需要加volatile吗?需要

    private DCL() {
    }

    public static void main(String[] args) {
        for(int i = 0;i<10;i++){
            new Thread(()->{
                System.out.println(DCL.getInstance().hashCode());
            }).start();

        }
    }
    public static DCL getInstance() {
        if (instance == null) {                     //first check
            synchronized (DCL.class) {
                if (instance == null) {             //second check
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    instance = new DCL();
                }
            }
        }
        return instance;
    }
}

2 Sync锁优化

  • 2.1 细化锁

尽量减小锁的粒度,即锁住的代码量,因为加锁性能会下降

  • 2.2 粗化锁

当一个方法中加了很多锁,则可以直接将方法锁住

3 CAS

Compare And Set (CAS)

  • 3.1 AtomicXXX 类

原子类 利用CAS保证线程安全,例如AtomicInteger类

  • 输出结果为10000
public class AtomicXXX {
    private static AtomicInteger count = new AtomicInteger(0);
    public static void main(String[] args) {
        List<Thread> threads = new ArrayList<>();
        for(int i = 0;i<10;i++){
            threads.add(new Thread(()->{
                increment();
            }));
        }
        threads.forEach((o)->o.start());
        threads.forEach((o)->{
            try {
                o.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println(count);
    }
    static void increment(){
        for(int i= 0;i<10000;i++){
            count.incrementAndGet();
        }
    }
}
  • 3.2 CAS原理

cas(value,Expected,Newvalue)
value 当前值,Expected 期望值,Newvalue新值
如果value != Expected ,继续调用cas;
如果value == Expected,则value = Newvalue;

*CAS可能存在ABA问题

可以通过给value 加时间戳或者版本号解决
A version1
B version2
A version3
对于基本数据类型ABA没有影响,但是对于对象可能产生问题,如果当前值为对象A,然后指向对象B(对象B操作了对象C),最后指向A,此时对C做的操作可能导致问题。

  • ABA对于对象引用可能导致的问题可以类比你和女友分手又复合,在分手期间女友做了什么你不知道,属于隐藏风险!

相关文章

网友评论

    本文标题:2 volatile、Sync优化和CAS

    本文链接:https://www.haomeiwen.com/subject/iugnfhtx.html