非阻塞队列之ConcurrentLinkedQueue
在并发编程中,有时间需要使用线程安全的队列。有两种方式:一种是使用阻塞算法,另一种是非阻塞算法。使用阻塞算法的队列可以用同一把锁(入队和出队同一把锁)或两把锁(入队和出队使用不同的锁)等方式来实现。非阻塞的实现方式则可以使用循环CAS的方式来实现。
ConcurrentLinkedQueue 是一个基于链表的无界非阻塞队列,线程安全,采用FIFO,底层数据结构采用单向链表实现,CAS非阻塞算法来保证线程安全(通过无限循环进行CAS尝试方法来代替阻塞算法挂起调用线程,相比阻塞算法,这是使用CPU资源来换取阻塞带来的开销)
- 1 入列出列线程安全,遍历不安全
- 2 不允许添加null元素
- 3 底层使用列表和CAS算法包装入列出列安全
- 4 使用场景: 当多个线程共享一个collection时 ConcurrentLinkedQueue是一个恰当的选择
public class ConcurrentQueue {
public static void main(String[] args) {
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
//计数器
final CountDownLatch countDownLatch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
newFixedThreadPool.execute(new Toyota(countDownLatch));
}
//关闭线程池
newFixedThreadPool.shutdown();
try {
//在主线程中调用await方法,主线程挂起,知道计数器为0
countDownLatch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主线程");
}
/**
* 模拟生产
*/
static class MQ{
private static Queue<String> queue = null;
public static Queue<String> initQueue(){
if (queue == null) {
queue = new ConcurrentLinkedQueue<String>();
}
String tasklist = "JH1,gj2,gd3,df4,gf5,trt6,gfd7,trt8,hg9,yt10";
String[] split = tasklist.split(",");
List<String> asList = Arrays.asList(split);
//数据入列
queue.addAll(asList);
return queue;
}
}
/**
* 模拟消费
*/
static class Toyota implements Runnable{
public CountDownLatch countDownLatch;
public Toyota(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
private static final Object object = new Object();
private static Queue<String> queueTya = MQ.initQueue();
@Override
public void run() {
while (true) {
synchronized (object) {
//数据出列
String poll = queueTya.poll();
if (poll ==null) {
break;
}
System.out.println(Thread.currentThread().getName()+"获取"+poll+",剩余"+queueTya.size()+"个任务");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
countDownLatch.countDown();
}
}
}