带回收功能的lockfree queue的java实现

本文介绍了一种无锁队列实现方式,该队列利用线程本地池进行节点分配和回收,有效减少了垃圾回收的压力,并通过原子操作确保了线程安全性。此外,还提供了一个测试用例来评估其性能。

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

/*
 * LockFreeQueueRecycle.java
 *
 
 *
 * From "Multiprocessor Synchronization and Concurrent Data Structures",
 * modify by juneshen ,base on the work of Maurice Herlihy and Nir Shavit.
 * 
 */

package june.shen;


import java.util.concurrent.atomic.AtomicStampedReference;

public class LockFreeQueueRecycle<T> {
  private AtomicStampedReference<Node> head;
  private AtomicStampedReference<Node> tail;
  ThreadLocal<Node> freeList = new ThreadLocal<Node>() {
    protected Node initialValue() { return null; };
  };
  /**
   * Create a new object of this class.
   */
  public LockFreeQueueRecycle() {
    Node sentinel = new Node();
    head = new AtomicStampedReference<Node>(sentinel, 0);
    tail = new AtomicStampedReference<Node>(sentinel, 0);
  }
  private Node allocate(T value) {
    int[] stamp = new int[1];
    Node node = freeList.get();
    if (node == null) { // nothing to recycle
      node = new Node();
    } else {            // recycle existing node
      freeList.set(node.next.get(stamp));
    }
    // initialize
    node.value = value;
    return node;
  }
  private void free(Node node) {
    Node free = freeList.get();
    node.next = new AtomicStampedReference<Node>(free, 0);
    freeList.set(node);
  }
  /**
   * Enqueue an item.
   * @param value Item to enqueue.
   */
  public void enq(T value) {
    // try to allocate new node from local pool
    Node node = allocate(value);
    int[] lastStamp = new int[1];
    int[] nextStamp = new int[1];
    int[] stamp = new int[1];
    while (true) {		 // keep trying
      Node last = tail.get(lastStamp);    // read tail
      Node next = last.next.get(nextStamp); // read next
      // are they consistent?
      if (last == tail.get(stamp) && stamp[0] == lastStamp[0]) {
        if (next == null) {	// was tail the last node?
          // try to link node to end of list
          if (last.next.compareAndSet(next, node,
              nextStamp[0], nextStamp[0]+1)) {
            // enq done, try to advance tail
            tail.compareAndSet(last, node,
                lastStamp[0], lastStamp[0]+1);
            return;
          }
        } else {		// tail was not the last node
          // try to swing tail to next node
          tail.compareAndSet(last, next,
              lastStamp[0], lastStamp[0]+1);
        }
      }
    }
  }
  /**
   * Dequeue an item.
   * @throws queue.EmptyException The queue is empty.
   * @return Item at the head of the queue.
   */
  public T deq() throws EmptyException {
    int[] lastStamp = new int[1];
    int[] firstStamp = new int[1];
    int[] nextStamp = new int[1];
    int[] stamp = new int[1];
    while (true) {
      Node first = head.get(firstStamp);
      Node last = tail.get(lastStamp);
      Node next = first.next.get(nextStamp);
      // are they consistent?
      if (first == head.get(stamp) && stamp[0] == firstStamp[0]) {
        if (first == last) {	// is queue empty or tail falling behind?
          if (next == null) {	// is queue empty?
            throw new EmptyException();
          }
          // tail is behind, try to advance
          tail.compareAndSet(last, next,
              lastStamp[0], lastStamp[0]+1);
        } else {
          T value = next.value; // read value before dequeuing
          if (head.compareAndSet(first, next, firstStamp[0], firstStamp[0]+1)) {
            free(first);
            return value;
          }
        }
      }
    }
  }
  /**
   * Items are kept in a list of nodes.
   */
  public class Node {
    /**
     * Item kept by this node.
     */
    public T value;
    /**
     * Next node in the queue.
     */
    public AtomicStampedReference<Node> next;
    
    /**
     * Create a new node.
     */
    public Node() {
      this.next  = new AtomicStampedReference<Node>(null, 0);
    }
  }
}
/*
 * EmptyException.java
 *
 * Created on December 28, 2005, 12:02 AM
 *
 * Copyright 2005 Sun Microsystems, Inc.  All Rights Reserved.
 *
 * Sun Microsystems, Inc. has intellectual property rights relating to technology embodied in the product that is described in this document.  In particular, and without limitation, these intellectual property rights may include one or more of the U.S. patents listed at http://www.sun.com/patents and one or more additional patents or pending patent applications in the U.S. and in other countries.
 * U.S. Government Rights - Commercial software.  Government users are subject to the Sun Microsystems, Inc. standard license agreement and applicable provisions of the FAR and its supplements.  Use is subject to license terms.
 * Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
 */

package june.shen;

/**
 * @author Maurice Herlihy
 */
public class EmptyException extends java.lang.Exception {
  
  /** Creates a new instance of EmptyException */
  public EmptyException() {
    super();
  }
  
}

package june.shen;

/**
 @author juneshen
 lockfree queue testsuit
 **/

public class LockFreeQueueTest {

	public  static LockFreeQueueRecycle<Integer> instance=new LockFreeQueueRecycle<Integer>();
	private static int THREADS=10;
	private static  Thread[] pushthread = new Thread[THREADS];
	private static  Thread[] popthread = new Thread[THREADS];
	
	public static void main(String[] args) {
		
		
		
		 long startTime;

			startTime = System.currentTimeMillis();
			
		    for (int i = 0; i < THREADS; i++) {
		    	pushthread[i] = new PushThread();
		    }
		    for (int i = 0; i < THREADS; i ++) {
		    	pushthread[i].start();
		    }
		    for (int i = 0; i < THREADS; i ++) {
		    	try {
					pushthread[i].join();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		    }
		    
		    Thread pushend= new Thread(new PushendThread());
		    pushend.start();
		    
		    for (int i = 0; i < THREADS; i++) {
		    	popthread[i] = new PopThread();
		    }
		    for (int i = 0; i < THREADS; i ++) {
		    	popthread[i].start();
		    }
		    for (int i = 0; i < THREADS; i ++) {
		    	try {
					popthread[i].join();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		    }
		    
		    long endTime = System.currentTimeMillis();
			double elapsedTime = ((double) (endTime - startTime)) / 1000.0;
			
			double throughput = ((double) THREADS*2 / elapsedTime);
		 
		    System.out.printf(" 吞吐量: %f, 运行时间: %f \n",throughput,elapsedTime);
	}

	

}

class PopThread extends Thread {
	
	    public void run() { 
	    	try {
	    		LockFreeQueueTest.instance.deq();
			} catch (EmptyException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	    }
	  }

class PushThread extends Thread {
	
	    public void run() { 
	    	LockFreeQueueTest.instance.enq(1);
	    }
}

class PushendThread extends Thread {
	
	    public void run() { 
	      for(int i=0;i<1000;i++)
	    	LockFreeQueueTest.instance.enq(i);
	    }
}


 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值