关键字-volatile volatile是Java提供的一种轻量级的同步机制,Java中包含两种同步机制: |-同步方法、同步代码块 synchronized一般被称为重量级锁 |-volatile变量,更轻量级,属于轻量级锁。因为它不会引起线程上下文的切换和调度。但是volatile变量的同步性比较差。也更容易出错。 作用:强制线程每次在使用的时候,都会看到共享区域的最新值 原子性: 原子性其实是Java并发变成的多个概念之一, 一次操作或多次操作中,要么所有的操作全部都得到了执行,并且不受到任何因素的干扰而中断。 要么所有的操作都不执行,多个操作步骤是一个不能分割的整体。 原子性就是拒绝多线程的,不论是单核还是多核,只要是具备原子性的量。同一时刻只能有一个线程对他进行操作。 整个操作过程中,不会被线程调度器中断的操作,都可以认为是具有原子性的。 比如:a=1,就是具有原子性的,a++或a+=1或a=a+1 他就不是原子性的操作。 Java中的原子性操作: 1、基本数据类型的读取和赋值操作,并且赋值必须是值给变量,变量之间的相互赋值就不属于原子性操作。 2、Java中提供了一个包,整个包里面所有的类都属于原子性操作:java.util.concurrent.atomic 可见性: 指的是当多个线程访问同一个变量的时候,一个线程改变了这个变量的值,其他线程能够立即看到修改的值。 在多线程环境下啊,一个线程对共享变量进行了操作对于其他线程是不可见的,Java提供了volatile来保证共享变量的可见性。 当一个变量被volatile修饰之后,表示线程的本地内存无效,当一个线程修改了共享变量之后它会立刻被更新到主内存中, 其他的线程读取共享变量的时候,就可以直接到主内存读取。 synchronized和Lock也可以保证共享变量的可见性。因为synchronized和Lock是保证同一时刻只有一个线程能够获取锁, 并且执行同步代码,并且在释放锁之前会对变量的修改进行刷新,刷新到主内存中,所以才能保证可见性。 volatile: 能够保证可见性,但是不能保证原子性。 当我们定义了一个volatile修饰的变量后,虚拟机会把这个线程的本地内存中变量强制的刷新到主内存中。 这个线程的写操作就会导致其他线程的volatile变量缓存无效。而是直接去主内存找变量。 volatile不能保证原子性。我们可以加锁,加锁之后,同一时间只能被一个线程执行,这种数据我们成为临界区数据,操作它的代码就称为临界区代码。 这样count++就成了原子操作。 原子性类:AtomicInteger AtomicInteger是从JDK1.5开始提供的java.util.concurrent.atomic里一个类,这个包里面的原子操作类提供了一种方法: 可以比较高效的,简单的更新一个变量的方式。 atomic里面提供了13种类,属于4种类型的原子更新方式,分别是: 原子更新基本数据类型 原子更新数组 原子更新引用 原子更新属性 原子更新基本数据类型: AtomicInteger 原子更新整数类型 AtomicBoolean 原子更新布尔类型 AtomicLong 源自更新长整数类型 以AtomicInteger类型举例: 构造方法: 无参构造:new AtomicInteger() 初始化一个默认值(0)的原子类型Integer 有参构造:new AtomicInteger(int v) 初始化一个指定参数的原子类型Integer 普通方法: int get() 获取值 int incrementAndGet() 以原子方式将当前的值+1,返回的是自增后的值 int addAndGet(int delta) 以原子方式将参数添加到值。以原子的方式将输入的值和对象中值相加,得到最后的结果。 int getAndSet(int value) 以原子方式设置为新的value值,并且把旧的值返回 AtomicInteger的内存分析以及基本原理 AtomicInteger原理是自旋锁+CAS算法 CAS算法全称是Compare And Swap 也就是 比较和交换。 算法公式 CAS(V,E,N) V:表示要更新的变量 E:表示预期的值 N:表示新值 如果V值等于E值,就把V的值设置为N,如果V值不等于E值,就说名已经有了其他线程完成了更新。 那么当前线程就什么都不做。就是CAS需要我们提供一个期望值,当期望值和当前线程的变量值相同, 说明还没有线程修改这个值,那么当前线程就可以进行修改,也就是执行CAS操作,如果期望值和 当前线程不符,说明这个值已经被其他线程修啊给i了,这个时候就不执行更新操作了,但是可以 重新选择读取这个变量,再次尝试修改这个变量,或者干脆放弃操作。 有3个操作数,内存的值V,表示要更新的变量。 旧的预期值E。要修改的值N 如果旧的预期值E==内存值V,表示修改成功,就是把V改为N 如果旧的预期值E!=内存值V,表示修改失败,不做任何操作。 并且重新获取现在的最新值,这个重新获取的动作就是【自旋】 乐观锁:CAS是从乐观状态的角度出发,它认为每次获取数据,别人都没有修改过,那么它就可以直接修改共享数据的值。 CAS不会上锁,只会在修改共享数据之前,检查一些别人有没有修改这个数据。 悲观锁:synchronized是一个悲观锁的状态,总是从最坏的角度出发,认为每次获取数据的时候,别人都有可能修改了数据,所以每次操作共享数据之前,都会上锁。 CAS和synchronized相同点,都可以保证共享数据的安全性。 不同点:CAS是乐观锁,synchronized是悲观锁。