关于线程安全

学习笔记,仅供自己参考,如有不对欢迎指正

1.关于内存模型

CPU高速缓存:因为CPU的执行速度要大于内存的读写速度,如果任何时候数据操作直接与内存交互,效率很低,所以出现了CPU高速缓存

CPU高速缓存的作用:程序执行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。

程序的原子性、可见性、有序性

  • 原子性:指一个操作是不可以中断的,不会被线程调度机制打断。
  • 可见性:指当一个线程修改共享变量的值时,其他线程会立刻知道这个指的修改
  • 有序性:指程序执行的顺序按照代码的先后顺序执行。

禁止指令重排
Java语言提供了volatilesynchronized两个关键字来保证线程之间操作的有序性
volatile关键字本身就包含了禁止指令重排序的语义
synchronized则是由“一个变量在同一个时刻只允许一条线程对其进行lock操作”这条规则获得的,这个规则决定了持有同一个锁的两个同步块只能串行地进入。

参考:https://www.cnblogs.com/guanghe/p/9206635.html

2.关于线程安全

  • 为什么会有线程安全?
    当多个线程同时访问统一代码(同一块对内存)的时候,会产生数据混乱的情况。
  • 如何保证线程安全?
    1.对非安全的代码进行加锁控制;
    2.使用线程安全的类;
    3.多线程并发情况下,线程共享的变量改为方法级的局部变量
  • synchronized和Lock的使用、区别及底层实现
    使用:都是对程序进行加锁,用来同步化代码块,保证线程安全
    区别:
    synchronized:
    1.加锁不可以中断
    2.synchronized可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象。
    lock:
    1.首先他是一个接口,可以中断
    2.需要显示指定起始位置和终止位置。
    3.一般使用ReentrantLock类做为锁,多个线程中必须要使用一个ReentrantLock类做为对象才能保证锁的生效。
    4.在加锁和解锁处需要通过lock()和unlock()显示指出。
    5.一般会在finally块中写unlock()以防死锁。
    底层实现:锁的本质,是对象内存堆中头部的一部分数据。当线程获得一个锁,即是在锁内存区域设置一些标志。线程释放锁也是改变这些标记。**
  • volatile的原理和使用方式
    原理:volatile保证了新值能立即同步到主内存,并且通知其他cpu核心,你们缓存中的数据无效了,这样所有cpu核心再想对该volatile变量操作首先会从主内存中重新拉取值,从而保证数据安全
    使用方式:volatile只保证了程序的可见性,但是不具备原子性。使用volatile必须满足下面两个条件:
    1.对变量的写操作不依赖于当前值
    2.该变量没有包含在具有其他变量的不变式中。
    适用场景举例: 用来做状态变量 由于boolean的赋值是原子性的,所以volatile布尔变量作为多线程停止标志还简单有效的.
class VolatileSimpleUse {

    private volatile boolean isOpenedDoor;

    public void openDoor() {
        isOpenedDoor = true;
    }

    public void doWork() {
        while (!isOpenedDoor) {
            // 门关了,你可以睡觉
        }
    }
}

参考:https://www.cnblogs.com/krcys/p/9385360.html

你可能感兴趣的:(关于线程安全)