生产者消费者是个经典的话题了,这次主要通过这个话题谈谈wait方法与sleep方法。
wait方法和sleep方法都是让出cpu占有权,让其它线程能够得到运行,不同的地方在于wait方法可以通过notify或者notifyAll方法主动唤醒或者wait一定的等待时间自动恢复运行,而sleep方法只能在等待一定的时间后自动恢复运行。
一般我们看到的生产者消费者实现都是通过wait、notify、notifyAll或者是condition接口的await、signal、signalAll方法实现的。这次我们想看看通过sleep方法实现与wait方法实现的效率有多大差别。
wait方式实现:
package pro_con;
import java.util.LinkedList;
public class QueueWithWait<T> extends BlockingQueue<T> {
private LinkedList<T> queue = new LinkedList<>();
private final int cacheSize;
public QueueWithWait(int cacheSize) {
super();
this.cacheSize = cacheSize;
}
public T take() {
synchronized (queue) {
while(true) {
if(queue.size()>0) {
T obj = queue.poll();
queue.notify();
return obj;
}else {
try {
queue.wait();
} catch (InterruptedException e) {
}
}
}
}
}
public void put(T obj) {
synchronized (queue) {
while (true) {
if (queue.size() < cacheSize) {
queue.offer(obj);
queue.notify();
break;
} else {
try {
queue.wait();
} catch (InterruptedException e) {
}
}
}
}
}
}
sleep方式实现:
package pro_con;
import java.util.LinkedList;
public class QueueWithSleep<T> extends BlockingQueue<T> {
private LinkedList<T> queue = new LinkedList<>();
private final int cacheSize;
public QueueWithSleep(int cacheSize) {
super();
this.cacheSize = cacheSize;
}
public T take() {
while (true) {
synchronized (queue) {
if (queue.size() > 0) {
T obj = queue.poll();
return obj;
} else {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
}
}
}
}
public void put(T obj) {
while (true) {
synchronized (queue) {
if (queue.size() < cacheSize) {
queue.offer(obj);
break;
} else {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
}
}
}
}
}
测试结果:
wait方式的前7次结果如下图所示
sleep方式的前7次结果如下图所示
结果是很明显的,wait方式比sleep方式效率要高出很多,可能会简单的认为sleep的时间过长导致的,那么把sleep方法去掉后结果如下:
结果发现效率与wait方式差不多,但是仔细观察会发现这种去掉sleep的方法结果是不稳定的,不像wait方法稳定在290万左右,原因是
去掉sleep方法后同一个put或者take方法在达到临界条件时有一定几率会多次循环,不像wait方法主动让出cpu占用权,从而降低了程序
的效率。
结论:
主流的生产者消费者模式还是用wait或者condition接口的await方式,但还有一种无锁队列会比这更加高效。
代码下载链接:https://pan.baidu.com/s/1ciLBNiIc9670cwdat2qspQ 密码:z5d1