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

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 list=new ArrayList();
		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并发编程的艺术,java)