一種簡單無鎖隊列的實現

Disruptor是內存無鎖併發框架,基於一個環數組作爲緩衝,詳見Disruptor-1.0

下面是自己設計的一個簡易版,目前沒有發現存在衝突或錯誤的測試用例。大家可以一起測試下。

package tianshui.lockfree.queue;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 併發生產者和消費者數不能多於queue的length,默認是2^16
 * @author 天水
 * @date 2013-4-9 上午11:42:10
 */
public class RingBuffer<T> implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6976960108708949038L;

	private volatile AtomicInteger head;
	
	private volatile AtomicInteger tail;
	
	private int length;
	
	final T EMPTY = null;
	
	private volatile T[] queue;
	
	public RingBuffer(Class<T> type, int length){
		this.head = new AtomicInteger(0);
		this.tail = new AtomicInteger(0);
		this.length = length == 0 ? 2 << 16 : length; // 默認2^16
		this.queue = (T[]) Array.newInstance(type, this.length);  
	}
	
	public void enQueue(T t){
		if(t == null) t= (T) new Object();
		// 阻塞 -- 避免多生成者循環生產同一個節點
		while(this.getTail() - this.getHead() >= this.length); 
		int ctail = this.tail.getAndIncrement();
		while(this.queue[this.getTail(ctail)] != EMPTY); // 自旋
		this.queue[this.getTail(ctail)] = t;
	}
	
	public T deQueue(){
		T t = null;
		// 阻塞 -- 避免多消費者循環消費同一個節點
		while(this.head.get() >= this.tail.get()); 
		int chead = this.head.getAndIncrement();
		while(this.queue[this.getHead(chead)] == EMPTY); // 自旋
		t = this.queue[this.getHead(chead)];
		this.queue[this.getHead(chead)] = EMPTY;
		return t;
	}
	
	public int getHead(int index){
		return index & (this.length - 1);
	}
	
	public int getTail(int index) {
		return index & (this.length - 1);
	}

	public int getHead() {
		return head.get() & (this.length - 1);
	}

	public int getTail() {
		return tail.get() & (this.length - 1);
	}

	public T[] getQueue() {
		return queue;
	}

	public int getLength() {
		return length;
	}

	public void setLength(int length) {
		this.length = length;
	}

}

下面是測試代碼:

package tianshui.lockfree.queue;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author 天水
 * @date 2013-4-9 下午04:13:29
 */
public class TestBuffer {
	public static AtomicInteger index = new AtomicInteger(0);
	
	public static void main(String[] args){
		
		int tCount = 10; // thread count
		int length = 0;  // buffer length -> 2^16
		
		final RingBuffer<Integer> buffer = new RingBuffer<Integer>(Integer.class, length);
		// provider
		Runnable pr = new Runnable(){
			@Override
			public void run() {
				while(true){
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					int tindex = index.getAndIncrement();
					buffer.enQueue(tindex);
					System.out.println("buffer enQueue: " + tindex);
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		};
		// consumer
		Runnable cr = new Runnable(){
			@Override
			public void run() {
				while(true){
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					Integer cindex = buffer.deQueue();
					System.out.println("buffer deQueue: " + cindex);
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		};
		
		for(int i=0; i<tCount; i++){
			new Thread(cr).start();
		}
		
		for(int i=0; i<tCount; i++){
			new Thread(pr).start();
		}
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章