Java:双缓冲队列

《程序员》:双缓冲队列就是冲着同步/互斥的开销来的。我们知道,在多个线程并发访问同一个资源的时候,需要特别注意线程的同步问题。稍稍不注意,哦活,程序结果不正确了。最经典的就是"银行取钱"的例子,想想,都跟现金挂上钩了,看来这真不容忽视。
今天我们要谈的不是如何去给资源加锁解锁来解决同步问题,今天的重点在于,如何将线程同步的开销降低到我们力所能及的程度。如果你觉得,你可以通过增加硬件资源来弥补程序开销,那么,你将不可能成为一个优秀的程序员。

进入正题,先引入一个例子,两个实体:一个是玩具工厂,它的工作就是不停地生产玩具;另外一个实体就是小孩,它的工作就是不停地从工厂拿玩具。小孩不可能直接到工厂去"拿"玩具吧?呵呵,妈妈是绝对不会放心的。所以,我们有一个"搬运工",搬运工自然要具备"存放"的功能,不然他怎么将玩具带给小孩呢,是吧。所以,我们先将搬运工定义为一个List,用来存放工厂生产出来的玩具。

玩具类,定义一个玩具实体 >>

复制代码
@Data
public class Toy {

    private String name;

}

生产玩具的玩具工厂,相当于生产者 >>

复制代码
public class Factory extends Thread {
    public void run() {
        while (true) {
            Toy toy = new Toy();
            toy.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");
            }
        }
    }
}

小孩取玩具,相当于消费者 >>

复制代码
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 >>

复制代码
public class DoubleBufferList {
	
	private List<Object> lp;
	private List<Object> 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();
	}
}

运行的主线程类 >>

复制代码
public class BaseTest {
	
	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();
	}
	
}

运行结果:比用一个List的生产者消费者模型快很多.大家可以测试下运行速度根据自己的实际情况进行使用

相关推荐
ikgy1 天前
JAVA EE:1.计算机是如何工作的
java·java-ee
.痞老板.1 天前
java ee--计算机是如何工作的
java·开发语言·java-ee
奇树谦1 天前
Qt Quick 图片加载与 GPU 纹理机制详解:QImage、QQuickTextureFactory、QSGTexture 与异步加载
开发语言·qt·系统架构
青梅味猪大肠1 天前
【操作系统-60】临近适应算法
java·linux·开发语言·嵌入式硬件·算法·操作系统
CoderYanger1 天前
Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)
java·数据库·spring·面试·职场和发展·java-ee·mybatis
程序员沉梦听雨1 天前
【搜索引擎】Kibana使用指南
java·后端·学习笔记
starzy19901 天前
深入理解Scala可变Map:动态构建场景下的性能与设计权衡
开发语言·scala
奶油话梅糖1 天前
打开项目 0.9 秒、内存只有 IDEA 的 1/12:OpenIDEA 用 Rust 把 IntelliJ IDEA 重造了一遍
java·rust·github·intellij-idea
vipxieliang1 天前
语言对比卡:PHP vs Go vs Java 的优缺点、适用场景与「为什么选 PHP」
java·go·php
Rain的Java大神之路1 天前
公交App上“还有2站,约5分钟”怎么实现?90%的人答错这道大厂面试题:GPS漂移、ETA不准、10万QPS热点读全拆透(附完整代码)
java·后端·面试