您的位置:首页 > 编程语言 > Java开发

Java并发机制的底层实现原理

2017-11-11 20:07 696 查看
Volatile

 它是轻量级的synchronized,比之执行成本更低,因为它不会引起线程的上下文切换,它在多处理器开发中保证了共享变量的“可见性”,“可见性”的意思是当一个线程修改一个变量时,另外一个线程能读到这个修改的值。

被volatile修饰的变量,在被执行赋值操作时,它使用lock前缀的汇编指令,保证

1,将当前处理器缓存行的数据写回到系统内存,

2,这个写回内存的操作会使其在其他CPU里缓存了该内存地址数据无效,这样其它cpu再想获取到该值时,会重新从内存中读取数据

上面两条规则,就是著名的“缓存一致性原则”

Synchronized

java中每一个对象都可以成为锁,具体表现为:

1,对于普通同步方法,锁是当前实例对象

2,对于静态同步方法,锁是当前类的class对象

3,对于同步方法块,锁是synchronized括号里配置的对象

同步代码块是使用monitorenter和monitorexit指令实现的,每个对象都有一个monitor与之相关联,当且仅当它被持有后,它将处于锁定状态

synchronized的锁存储在java对象头里面,锁一共有4中状态,依次是:无锁状态<偏向锁状态<轻量级锁状态<重量级锁状态, 另外随着竞争情况,锁会升级,而且升级后不能降级,这样做是为了保证获得锁和释放锁的效率.

偏向锁: 现实中锁不仅不存在多线程竞争,而且总是被同一个线程获得,为了降低线程获得锁的开销,引入偏向锁。偏向锁的撤销只有当竞争出现的时候才会发生。

轻量级锁:通过CAS自旋的方式,没有获取资源的线程不必阻塞,也就不会有上下文的切换,从而降低了开销,但是CAS自旋也是消耗CPU的,所以轻量级锁使用于同步块执行速度快,锁的持有时间比较短的情况,响应速度比较快

重量级锁:线程之间竞争不存在自旋的情况,直接阻塞,上下文切换,系统开销比较大,适用于同步块所需要的时间比较久的情况,系统吞吐量比较大

原子操作的实现原理

理解几个术语

1,缓存行,cache line,缓存的最小操作单位

2,比较并交换,compare and exchange, CAS操作需要输入两个值,一个old value(也是expected value),一个new value,在操作期间,如果旧值发生了变化,则新值不会交换,这个就是为了解决例如 i++这种情况的,i读取,i++, i被赋值,但是如果多个线程同时访问这个i值,则下一个线程读取到的可能是脏数据,这时候新值就不该被赋给变量,自旋CAS的实现原理就是,当这种情况发生时,放弃赋值,重新尝试,直到成功为止

3,CPU流水线,一条指令被分解成多个步骤,每个步骤在不同的电器元件上执行,类似于车间流水线,这样可以提高效率

4,内存顺序冲突,这个概念我稍微有点疑惑,它是由假共享引起的,是指多个CPU同时修改一个缓存行的不同部分引起其中一个CPU的操作无效,当出现这种情况时,CPU流水线会被清空,这个清空我自己的理解是说,后续指令需要依赖前面指令才能成功,如果前面缓存更新失效了,后续指令需要重新执行

处理器如何实现原子操作呢

1,总线加锁实现原子操作

2,缓存加锁实现原子操作

Java如何实现原子操作呢

1,使用循环CAS实现原子操作

2,使用锁实现原子操作

下面附上一段循环CAS代码

import java.sql.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicJava {

private static AtomicInteger atomicI = new AtomicInteger();
private static int i = 0;

public void count(){

/* 自旋CAS(compareAndSet)的基本思路就是循环进行CAS操作直到成功为止
* atomicI.getAndIncrement();
public final int getAndIncrement() {
for (;;) {//
int current = get();
int next = current + 1;// current和next不存在被竞争的情况,但是get()获取到执行compareAndSet之间,很可能原值已经被其它线程改变了
if (compareAndSet(current, next))
return current;
}
}*/
}

public static void main(String[] args){
final AtomicJava counter=new AtomicJava();
List<Thread> list=new ArrayList<Thread>();
for(int i=0;i<100;i++){
Thread t=new Thread(new Runnable(){
@Override
public void run() {
for(int j=0;j<1000;j++){
counter.safeCount();
counter.unSafeCount();
}
}
});
list.add(t);

}
for(Thread t:list){
t.start();
}

try {
Thread.sleep(1000);
for (Thread t : list) {
t.join();
}
System.out.println("Unsafe count: "+i);
System.out.println("Safe count: "+atomicI.get());
} catch (InterruptedException e) {
e.printStackTrace();
}
}

/**
* 使用CAS实现线程安全计数器
*/
private void safeCount() {
for (;;) {
int i = atomicI.get();
boolean suc = atomicI.compareAndSet(i, ++i);
if(suc)
return;
}
}

/**
* 非线程安全的count
*/
private void unSafeCount(){
i++;
}
}


输出结果:

Unsafe count: 99498

Safe count: 100000

Java中有很多原子操作类,如AtomicInteger,AtomicBoolean,它们都是使用自旋CAS实现原子操作的。可以查看AtomicInteger.getAndIncrement()源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  并发 java