前段时间,做了个“双缓冲队列”,可是测试的效果就是不怎么明显,理论完全都在这里,可是就是看不到效果。 昨天在某某的提示下,终于意识到不该用阻塞队列,换成普通的List对象,这样效果就明显多啦~~ 又重新写了一篇文档,如下提出问题:为啥要有双缓冲队列?
引用09年9月《程序员》上的一句话:双缓冲队列就是冲着同步/互斥的开销来的。我们知道,在多个线程并发访问同一个资源的时候,需要特别注意线程的同步问题。稍稍不注意,哦活,程序结果不正确了。最经典的就是“银行取钱”的例子,想想,都跟现金挂上钩了,看来这真不容忽视。
今天我们要谈的不是如何去给资源加锁解锁来解决同步问题,今天的重点在于,如何将线程同步的开销降低到我们力所能及的程度。如果你觉得,你可以通过增加硬件资源来弥补程序开销,那么,你将不可能成为一个优秀的程序员。 进入正题,先引入一个例子,两个实体:一个是玩具工厂,它的工作就是不停地生产玩具;另外一个实体就是小孩,它的工作就是不停地从工厂拿玩具。小孩不可能直接到工厂去“拿”玩具吧?呵呵,妈妈是绝对不会放心的。所以,我们有一个“搬运工”,搬运工自然要具备“存放”的功能,不然他怎么将玩具带给小孩呢,是吧。所以,我们先将搬运工定义为一个List,用来存放工厂生产出来的玩具。
玩具类,定义一个玩具实体 public class Toy { private String name;
public String getName() { return name; } public void setName(String name) { this.name = name; } }
生产玩具的玩具工厂,相当于生产者 package twoBufferQueue;
public class Factory extends Thread { public void run() { while (true) {
Toy t = new Toy();
t.setName("玩具"); synchronized (Tools.lP) { if (Tools.lP.size() >= 2000) { try { Tools.lP.wait(); } catch (Exception e) { // TODO: handle exception } } Tools.lP.add(t); // System.out.println("put one"); } }
} }
小孩取玩具,相当于消费者
package twoBufferQueue;
public class Kid extends Thread { long time1 = System.currentTimeMillis(); int count = 0;
public void run() { while (true) {
synchronized (Tools.lT) { if (Tools.lT.size() != 0){ Tools.lT.remove(0); count++; } } if (count == 100000) { System.out.println("time:" + (System.currentTimeMillis() - time1)); System.exit(0); }
} }
}
双缓冲队列,里面有两个List
package twoBufferQueue;
import java.util.List;
public class DoubleBufferList { private List lP; private List lT; private int gap;
public DoubleBufferList(List lP, List lT, int gap) { this.lP = lP; this.lT = lT; this.gap = gap; }
public void check() { Runnable runner = new Runnable() { public void run() { while (true) { if (lT.size() == 0) { synchronized (lT) { synchronized (lP) { lT.addAll(lP); lP.notifyAll(); } lP.clear(); } } } } }; Thread thread = new Thread(runner); thread.start(); }
}
运行的主线程类:
package twoBufferQueue;
public class MainTest { public static void main(String[] args) { Factory f = new Factory(); f.start(); Kid k = new Kid(); k.start(); new DoubleBufferList(Tools.lP,Tools.lT,1).check(); } }
运行结果:time:265毫秒 确实很快,比用一个List的生产者消费者模型快很多,不至几倍...强烈建议大家使用。