cas 循环数组

本文介绍了一种基于CAS的无锁多读多写循环队列实现方式,该队列利用原子操作确保数据一致性,适用于高并发场景。文章详细阐述了队列的基本操作如放置元素和获取元素的方法,并提供了完整的Java实现代码及测试示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自己测试通过的cas版本的多读多写的无锁模式的循序队列


import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReferenceArray;

/*cas的缓存循环数组,
 * 存数据:采用先占用位置,然后在放数据的原则.
 * 取数据:采用先取数据,置为cas置为空,然后在将读指针加一的原则,
 * 		需要注意的时候,由于是循环数组,取出来数据不为空,有可能已经是又被放进去的数据了.要保证当前reader指针没被改变的情况下才可以去cas改变置为空.
 * @auth zhangwy 
 * */
public class MpsQueue<T> {
	protected AtomicLong readerIndex;
	protected AtomicLong writerIndex;
	protected final int size ;
	protected final int mask ;
	AtomicReferenceArray<T> buffer = null;
	public MpsQueue(int length) {
		size = MathUtil.roundToPowerOfTwo(length) ;
		mask = size - 1;
		buffer = new AtomicReferenceArray<T>(size);
		readerIndex = new AtomicLong(0);
		writerIndex = new AtomicLong(0);
	}
	//idx % size
	public int idx(long index) {
		return (int) (index & mask);
	}
	//读指针获取
	public long getReaderIndex() {
		return readerIndex.get();
	}
	//写指针获取
	public long getWriterIndex() {
		return writerIndex.get();
	}
	/*放置元素*/
	public boolean put(T element) {
		long reader ,writer ;
		long wrapSize ;
		if(element == null)	{
			throw new IllegalArgumentException("element can't not be null");
		}
		do {
			reader = getReaderIndex();
			writer = getWriterIndex();
			wrapSize = writer - reader ;
			//仍有空间放置
			if(wrapSize < size) {
			} else {
				return false;
			}
		} while(!writerIndex.compareAndSet(writer, writer + 1));
		int offset = idx(writer);
		if(buffer.get(offset) != null) {
			throw new RuntimeException("buffer @" + writer + " must be null,but now is not null");
		}
		buffer.set(offset, element);
		return true;
	}
	/**
	 ** get a element from the queue 
	 ***/
	public T get() {
		T element  = null;
		long reader ,writer ;
		int offset;
		do {
			reader = getReaderIndex() ;
			writer =  getWriterIndex();
			/*queue不为空*/
			if(writer == reader) {
				return null;
			}
			offset = idx(reader);
			element = buffer.get(offset);
			/*元素已经被取走了*/
			if(element == null ) continue;
			/*reader已经是最新*/
			if(reader == getReaderIndex() && buffer.compareAndSet(offset, element, null)) {
				//System.out.println("pop :" +reader +":"+ offset + ":" + element);
				break;
			}
		}while(true);
		if(element != null) {
			while(!readerIndex.compareAndSet(reader, reader + 1)){
				throw new RuntimeException(String.format("readerIndex is %d has been changed,is error", readerIndex));
			}
			return element;
		}
		return null;
	}
	/**
	 * 
	 */
	
}


public class MathUtil {
    public static int log2p(int x) {
        int r = 0;
        while ((x >>= 1) != 0)
            r++;
        return r;
    }
    public static int roundToPowerOfTwo(int x) {
    	x --;
    	x |= x >>>  1;
	    x |= x >>>  2;
	    x |= x >>>  4;
	    x |= x >>>  8;
	    x |= x >>> 16;
	    x++;
	    if (x < 0) {
	        x >>>= 1;
	    }
    	return x;
    }
    public static void main(String[] args) {
		System.out.println(roundToPowerOfTwo(699999999));
	}
}

测试代码



package io.mycat.bigmem.buffer;

import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicLong;

import org.junit.Test;

import io.mycat.bigmem.util.MpsQueue;

/**
*@desc
*@author zhangwy   @date 2017年1月2日 下午6:02:44
**/
public class DirectByteBufferTest {
	
	@Test
	public void testMPIMulThread() {
		int length = 16;
		MpsQueue<Integer> array = new MpsQueue<Integer>(length );
		ReadThread readThread = new ReadThread(array);
		readThread.start();
		ReadThread readThread1 = new ReadThread(array);
		readThread1.start();
		new WriteThread(0, 1000000000, array).start();
		new WriteThread(1000000000, 2000000000, array).start();
		new WriteThread(2000000000, 2100000000, array).start();
//		new WriteThread(3000000000, 4000000000, array).start();
		//new WriteThread(400000, 500000, array).start();

		while(readThread.isAlive()){
			try {
				Thread.currentThread().sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
}
class WriteThread<Integer> extends Thread {
	protected int start;
	protected int end;
	protected MpsQueue<Integer> queue;
	public WriteThread(int start ,int end,MpsQueue<Integer> queue) {
		this.start = start;
		this.end = end;
		this.queue = queue;
	}
	@Override
	public void run() {
		int content = start;
		for(; content < end;) {
			final Integer  p = (Integer) new java.lang.Integer(content);
			if(queue.put(p)) {
				content ++;
			} else {
				try {
					Thread.currentThread().sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		System.out.println("======" + content);
	}
}

class ReadThread<Integer> extends Thread {
	protected AtomicLong count ;
	MpsQueue<Integer> queue = null;
	public ReadThread(MpsQueue<Integer> queue) {
		this.queue = queue;
		count = new AtomicLong();
	}
	@Override
	public void run() {
		Integer element = null;
		while(true) {
			
			while((element = queue.get()) != null) {
				count.incrementAndGet();
			}
			System.out.println(count.get());
			;
			try {
				Thread.currentThread().sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值