- 在共享内存的多处理器体系架构中,每一个处理器都拥有本身的缓存,而且按期地与主内存进行协调。
- 在不一样的处理器架构中提供了不一样级别的缓存一致性(Cache Coherence),
- 其中一部分只提供最小的保证,即容许不一样的处理器在任意时刻从同一个存储位置上看到不一样的值。
- 操做系统、编译器以及运行时(有时甚至包括应用程序)须要弥合这种在硬件能力与线程安全之间的差别。
java内存模型java
- 抽象出线程独有的运行内存和共有的主存储
- 为了使java开发人员无须关心不一样架构内存模型之间的差别,
- Java还提供了本身的内存模型,而且JVM经过在适当的位置上插入内存栅栏(内存屏障)来屏蔽在JVM与底层之平台内存模型之间的差别。
- 线程中的变量什么时候同步回到内存是不可预期的
- java内存模型规定,经过关键词”synchronized“、”volatile“可让java保证某些约束。
- “volatile” - 保证读写的都是主内存变量。
- “synchronized” - 保证在块开始时,都同步主内存值到工做内存,而快结束时,将工做内存同步会主内存。
指令重排序::数组
public class PossibleReordering {
static int x = 0, y = 0;
static int a = 0, b = 0;
public static void main(String[] args) throws InterruptedException {
Thread one = new Thread(new Runnable() {
@Override
public void run() {
a = 1;
x = b;
}
});
Thread two = new Thread(new Runnable() {
@Override
public void run() {
b = 2;
y = a;
}
});
one.start();
two.start();
one.join();
two.join();
System.out.println("x:" + x + ",y:" + y);
}
}
- 执行结果,通常人可能认为是1,1;真正的执行结果可能每次都不同。
- 拜JMM重排序所赐,JMM使得不一样线程的操做顺序是不一样的,
- 从而致使在缺少同步的状况下,要推断操做的执行结果将变得更加复杂。
- 同步将限制编译器和硬件运行时对内存操做重排序的方式。
锁synchronized
- 锁实现了对临界资源的互斥访问,是严格的排它锁、互斥锁。
- JVM规范经过两个内存屏障(memory barrier)命令来实现排它逻辑。
- 内存屏障能够理解成顺序执行的一组CPU指令,彻底无视指令重排序。
- 类锁(锁是TestSTatic.class对象)、对象锁
独占锁
- 若是你不敢肯定该用什么锁,就用这个吧,在保证正确的前提下,后续在提升开发效率。
分拆锁
- 若是将这些锁请求分到更多的锁上,就能有效下降锁竞争程度。
- 因为等待而被阻塞的线程将更少,从而可伸缩性将提升。
- 同时使用俩
分离锁
- 在某些状况下,能够将锁分解技术进一步扩展为对一组独立对象上的锁进行分解,这种状况称为锁分段
- 例如ConcurrencyHashMap是有一个包含16个锁的数组实现
- 锁分段的劣势在于:
- 与采用单个锁来实现独占访问相比,
- 要获取多个锁来实现独占访问将更加困难而且开销更高,
- 好比计算size、重hash。
分布式锁
- zookeeper,判断临时节点是否存在,存在就说明已经有人争抢到锁;
- 不存在就建立节点,代表拥有该锁。
volatile
- volatile是比synchronized更轻量级的同步原语,
- volatile能够修饰实例变量、静态变量、以及数组变量(引用)。
- 被volatile修饰的变量,JVM规范规定,一个线程在修改完,另外的线程能读取最新的值。
- 仅仅保证可见性,不保证原子性