缓冲区是一块特定的内存区域,开辟缓冲区的目的是通过缓存来缓解应用程序上下层之间的性能差异,提高系统性能
漏斗的初始口径很大,并且拥有一定的容量,因此茶壶中的水可以先倒入漏斗中,就像内存中的数据先写入一块缓冲区。只要漏斗够大,茶壶里的水很快就能倒完。至此,上层系统完成工作,可以去处理其他业务逻辑。而此时,大部分水在漏斗中,可以有下层系统慢慢处理,直至水完全进入瓶中,漏斗(缓冲区)被清空
基于这种结构,加快了上层组件的处理速度,从而提升了整体性能
缓冲可以协调上层组件和下层组件的性能差,当上曾组建性能优于下层组件时,可以有效减少上层组件对下层组件的等待时间
缓冲最常用的场景就是提高I/O的速度
// 不使用缓冲
writer = new FileWriter(new File("file.text"));
// 使用缓冲
writer = new BufferedWriter(new FileWriter(new File("file.text")));
一般来说,缓冲区不宜过小,过小的缓冲区无法起到真正的缓冲作用,缓冲区也不宜过大,过大的缓冲区会浪费系统能吃,增加GC负担
另一个典型例子是使用缓冲区提升动画显示效果
// 画一个左右平移的圆球
public class NoBufferMovingCircle extends JApplet implements Runnable {
Image screenImage = null;
Thread thread;
int x = 5;
int move = 1;
@Override
public void init() {
screenImage = createImage(230, 160);
}
@Override
public void start() {
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
@Override
public void run() {
try {
while (true) {
x += move;
if ((x > 105) || (x < 5)) {
move *= -1;
}
repaint();
Thread.sleep(200);
}
} catch (Exception e) {
}
}
public void drawCircle(Graphics gc) {
Graphics2D g = (Graphics2D)gc;
g.setColor(Color.green);
g.fillRect(0, 0, 200, 100);
g.setColor(Color.red);
g.fillOval(x, 5, 90, 90);
}
@Override
public void paint(Graphics g) { // 画一个圆,这里没有缓冲
g.setColor(Color.white);
g.fillRect(0, 0, 200, 100);
drawCircle(g);
}
}
以上代码虽然没有main函数,但是在Eclipse中可以通过Run As下的Java Applet运行(IDEA你看看人家)
此时虽然可以完成平移,但是效果较差,因为每次的界面刷新都涉及图片的重新绘制,而这是较为费时的操作,因此画面的抖动和白光效果明显,为了得到更好的效果可以加上缓冲区
public class BufferMovingCircle extends NoBufferMovingCircle {
Graphics doubleBuffer = null; // 缓冲区
@Override
public void init() {
super.init();
doubleBuffer = screenImage.getGraphics();
}
@Override
public void paint(Graphics g) { // 使用缓冲区,优化原有的paint()方法
doubleBuffer.setColor(Color.white); // 现在内存中画图
doubleBuffer.fillRect(0, 0, 200, 100);
drawCircle(doubleBuffer);
g.drawImage(screenImage, 0, 0, this); // 将buffer一次性显示出来
}
}
除了性能上的优化,缓冲区还可以作为上层组件和下层组件的一种通讯工具,从而将上层组件和下层组件进行解耦,优化设计模式。在 “生产者消费者模式” 中,连接生产者消费者的缓冲区正是起这个作用