欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java高并发之CAS无锁

程序员文章站 2022-05-04 10:52:48
...

java高并发之CAS无锁

无锁类的原理

1.CAS

      CASCompare andSwap方法包含三个参数(V,E,N) :V表示要更新的变量,E表示预期的值,N表示新值。仅当V的值等于E时,才会将V的值修改为N。如果V的值不等于E,说明已经被其他线程修改了,当前线程可以放弃此操作,也可以再次尝试次操作直至修改成功。基于这样的算法,CAS操作即使没有锁,也可以发现其他线程对当前线程的干扰,并进行恰当的处理。

2.CPU指令

       有的人会问了CAS操作是不是有Bug, 由于CAS操作时会先读取一个值,然后比较,然后再设置,他就会认为数据在读取比较之后还未进行设值之前,这个时候有个新的线程进来,把这个数据修改了,也就说他认为CAS步骤太多,担心在造作的时候被其它线程干扰,认为不是一个合适的方案。其实这个担心是多余的,因为CAS整的操作过程是原子操作(Atomic)它是由一条CPU指令完成的,并不是读数据取数据比较数据设置数据好多CPU指令完成的。

java高并发之CAS无锁

无锁类

1.AtomicInteger

我们进入AtomicInteger类里面可以看到很多方法

java高并发之CAS无锁

我们随便找一个方法看一看:

java高并发之CAS无锁

从注释中可以看出getAndincrement()方法返回一个当前值,并将当前值加1 。

这个方法这里可以看到 for的死循环,首先获取(get)当前值current,然后对着值进行加1,next值可能当前值(current)+1,也可能是已经被改过的值。然后进行判断,如果next不是当前值(current)+1,则继续For循环;如果是当前值(current)+1,则返回当前值(current)。


package com.nliki.www;

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerDemo {
	static AtomicInteger i=new AtomicInteger();
	public static class AddThread implements Runnable{
		@Override
		public void run(){
			for(int k=0;k<10000;k++){
				i.incrementAndGet();
			}
		}
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) throws InterruptedException{
		// TODO Auto-generated method stub
		Thread[] t=new Thread[10];
		for(int k=0;k<10;k++){
			t[k]=new Thread(new AddThread());
		}
		for(int k=0;k<10;k++){
			t[k].start();
		}
		for(int k=0;k<10;k++){
			t[k].join();
		}
		System.out.println(i);

	}

}

结果:

java高并发之CAS无锁

2.unsafe

unsafe从字面上就知道这是不安全的,java相对于C,C++来说,相对比较安全,因为它将有关指针一些内容屏蔽掉了,而unsafe恰恰相反,它相对于java底层它会提供一些类似指针操作,unsafe主要应用在jdk内部,进行一些位运算。它提供的一般是根据偏移量设置值,我们可以在AtomicInteger看到这样的方法objectFieldOffset,objectFieldOffset类似于C中的结构体struct

java高并发之CAS无锁

比如:在C中有一个这样一个结构体struct,我们定义一个Int a、int b

java高并发之CAS无锁

而java里是对Class

java高并发之CAS无锁

3.AtomicReference

AtomicReference和AtomicInteger 相比,AtomicInteger 封装的是一个整数,而AtomicReference封装的是一个对象的引用,从AtomicReference我们可以看出public class AtomicReference<V>,V可以是任意模板,他也有一些类似AtomicInteger 方法。

java高并发之CAS无锁

package com.nliki.www;

import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceDemo {
	public final static AtomicReference<String> atomicStr=new AtomicReference<String>("Nliki");
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		for(int i=0;i<10;i++){
			new Thread(){
				public void run(){
					try{
						Thread.sleep(Math.abs((int)(Math.random()*100)));
					}catch(InterruptedException e){
						e.printStackTrace();
					}
					if(atomicStr.compareAndSet("Nliki", "NanHui")){
						System.out.println("Thread:"+Thread.currentThread().getId()+" Change value to NanHui ");
					}else{
						System.out.println("Thread:"+Thread.currentThread().getId()+" FAILED");
					}
				}
			}.start();
		}

	}

}

运行结果:

java高并发之CAS无锁

4.AtomicStampedReference

 AtomicStampedReference从字面Stamped上可以看出他是一个带有邮戳的。下面我们可以AtomicStampedReference有什么用。如果下面这样张图我们没有用到AtomicStampedReference方法,我们是很难知道中间有值得改变。

java高并发之CAS无锁


package com.nliki.www;

import java.util.concurrent.atomic.AtomicStampedReference;

public class AtormicStampedReferenceDemo {
	static AtomicStampedReference<Integer> money=new AtomicStampedReference<Integer>(19,0);
	/**
	 * @param args
	 */
	public static void main(String[] args) throws InterruptedException{
		// TODO Auto-generated method stub
		for(int i=0;i<3;i++){
			final int timestamp=money.getStamp();
			new Thread(){
				public void run(){
						while(true){
							Integer m=money.getReference();
							if(m<20){
								if(money.compareAndSet(m, m+20, timestamp, timestamp+1)){
									System.out.println("余额小于20元,充值成功,余额:"+ money.getReference()+"元");
									break;
								}else{
									break;
								}
							}else{
								break;
							}
						}
				}
			}.start();
			
			new Thread(){
				public void run(){
					for(int i=0;i<20;i++){
						while(true){
							int timestamp=money.getStamp();
							Integer m=money.getReference();
							if(m>10){
								System.out.println("大于10元");
								if(money.compareAndSet(m, m-10, timestamp, timestamp+1)){
									System.out.println("成功消耗10元,余额:"+money.getStamp());
									break;
								}
							}else{
								System.out.println("没有足够的金额");
								break;
							}
						}
						try{
							Thread.sleep(100);
						}catch(InterruptedException e){
							e.printStackTrace();
						}
					}
				}
			}.start();
			
		}
	}

}

运行结果:

java高并发之CAS无锁

从运行结果中我们可以看到我们只充值了一次。

5.AtomicIntegerArray

AtomicIntegerArray 和AtomicInteger 区别 很显然是数组

package com.nliki.www;

import java.util.concurrent.atomic.AtomicIntegerArray;

public class AtomicIntegerArrayDemo {
	static AtomicIntegerArray arr=new AtomicIntegerArray(10);
	
	public static class AddThread implements Runnable{
		@Override
		public void run(){
			for(int i=0; i<100000;i++){
				arr.getAndIncrement(i%arr.length());
			}
		}
	}
	/**
	 * @param args
	 */
	public static void main(String[] args)throws InterruptedException {
		// TODO Auto-generated method stub
		Thread[] ts=new Thread[10];
		for(int i=0;i<10;i++){
			ts[i]=new Thread(new AddThread());
		}
		for(int i=0;i<10;i++){ts[i].start();}
		for(int i=0;i<10;i++){ts[i].join();}
		System.out.println(arr);
	}

}

运行结果:

java高并发之CAS无锁

6.AtomicIntegerFieldUpdater

package com.nliki.www;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

public class AtomicIntegerFieldUpdaterDemo {
	public static class Candidate {
		int id;
		volatile int score;
	}

	public final static AtomicIntegerFieldUpdater<Candidate> scoreUpdater = AtomicIntegerFieldUpdater
			.newUpdater(Candidate.class, "score");
	
	//我们用AtomicInteger验证Updater是否正确
	public static AtomicInteger allScore = new AtomicInteger(0);

	public static void main(String[] args) throws InterruptedException{
		final Candidate stu = new Candidate();
		Thread[] t = new Thread[10000];
		for (int i = 0, len = t.length; i < len; i++) {
			t[i] = new Thread() {
				public void run() {
					if (Math.random() > 0.4) {
						scoreUpdater.incrementAndGet(stu);
						allScore.incrementAndGet();
					}
				}
			};
			t[i].start();
		}
		for (int i = 0, len = t.length; i < len; i++) {
			t[i].join();
		}
		System.out.println("score="+stu.score);
		System.out.println("allScore="+allScore);

	}

}

运行结果:

java高并发之CAS无锁

相关标签: CAS Java 无锁