2008年10月8日星期三

性能敏感的环境下用日志要小心

昨天用Profiler跑CPU负载时发现某个函数占用的CPU特别的多……但是函数本身没有什么特别之处,只是调用十分频繁(但是不止这一个函数调用频繁),最后吧焦点锁定到了日志记录上(好像经常跟上面栽跟头啊)
本来是用String.format格式化了一个字符串,然后再传到logger里面的,但是这个logger已经被关掉了。所以问题出在String.format上,屏蔽掉这个东西以后果然CPU占用立刻减少。
但是日志怎么办呢,Log4j的logger提供了isXXXEnabled方法,外面加个if就搞定了

2008年10月4日星期六

还是JFC,还是实时曲线图,就是加入了一个封装。




/*
* Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
* Release under GNU/GPL Version 2.
*/

package cn.bearice.ipcontroller.manager.graph;

/**
*
* @author Bearice
*/
public interface RealTimeGraphDataSouce {
public Number getDate();
}


/*
* RealTimeGraphPanel.java
*
* Created on 2008年10月1日, 下午2:04
*/
package cn.bearice.ipcontroller.manager.graph;

import cn.bearice.java.util.StopableThread;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;

/**
*
* @author Bearice
*/
public class RealTimeGraphPanel extends javax.swing.JPanel {

private static final long serialVersionUID = 8250077948583513551L;
private TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection();
private JFreeChart jFreeChart = ChartFactory.createTimeSeriesChart(null, null, null, timeSeriesCollection, true, true, false);
private ChartPanel chartPanel = new ChartPanel(jFreeChart);
private XYPlot xyplot = jFreeChart.getXYPlot();
private LinkedHashMap tss = new LinkedHashMap();
private Class timeClass = Millisecond.class;
private long updateRate = 1000;
private long fixedDisplayRange = 50000;
private int maxSimpleCount = 10000;
private long maxSimpleAge = Long.MAX_VALUE;

public int getMaxSimpleCount() {
return maxSimpleCount;
}

public synchronized void setMaxSimpleCount(int maxSimpleCount) {
int old = this.maxSimpleCount;
this.fixedDisplayRange = maxSimpleCount;
Collection t = new ArrayList(tss.values());
for (TimeSeries timeSeries : t) {
timeSeries.setMaximumItemCount(maxSimpleCount);
}
firePropertyChange("maxSimpleCount", old, maxSimpleCount);
}

public long getMaxSimpleAge() {
return maxSimpleAge;
}

public synchronized void setMaxSimpleAge(long maxSimpleAge) {
long old = this.maxSimpleAge;
this.maxSimpleAge = maxSimpleAge;
Collection t = new ArrayList(tss.values());
for (TimeSeries timeSeries : t) {
timeSeries.setMaximumItemAge(maxSimpleAge);
}
firePropertyChange("maxSimpleAge", old, maxSimpleAge);
}

public long getFixedDisplayRange() {
return fixedDisplayRange;
}

public synchronized void setFixedDisplayRange(long fixedDisplayRange) {
long old = this.fixedDisplayRange;
this.fixedDisplayRange = fixedDisplayRange;
if (jrdoFixed.isSelected()) {
jrdoFixedActionPerformed(null);
}
firePropertyChange("fixedDisplayRange", old, fixedDisplayRange);
}

public long getUpdateRate() {
return updateRate;
}

public synchronized void setUpdateRate(long updateRate) {
long old = this.updateRate;
this.updateRate = updateRate;
if (t1 != null) {
t1.interrupt();
}
firePropertyChange("updateRate", old, updateRate);
}

public void setTitle(String text) {
jFreeChart.setTitle(text);
}

public TextTitle getTitle() {
return jFreeChart.getTitle();
}

public void setTitle(TextTitle title) {
jFreeChart.setTitle(title);
}

public Class getTimeClass() {
return timeClass;
}

protected void setTimeClass(Class timeClass) {
this.timeClass = timeClass;
}

public String getXLable() {
return xyplot.getDomainAxis().getLabel();
}

public void setXLable(String xLable) {
xyplot.getDomainAxis().setLabel(xLable);
}

public String getYLable() {
return xyplot.getRangeAxis().getLabel();
}

public void setYLable(String yLable) {
xyplot.getRangeAxis().setLabel(yLable);
}

public RealTimeGraphPanel() {
}

public RealTimeGraphPanel(Class timeClass) {
setTimeClass(timeClass);
}

public RealTimeGraphPanel(String title, String xLable, String yLable) {
setTitle(title);
setXLable(xLable);
setYLable(yLable);
init();
}

/** Creates new form RealTimeGraphPanel */
public RealTimeGraphPanel(Class timeClass, String title, String xLable, String yLable) {
this(timeClass);
setTitle(title);
setXLable(xLable);
setYLable(yLable);
init();
}

public synchronized void init() {
ValueAxis valueaxis = xyplot.getDomainAxis();
valueaxis.setAutoRange(true);
valueaxis = xyplot.getRangeAxis();
valueaxis.setAutoRange(true);
initComponents();
}

public synchronized void addTimeSeries(RealTimeGraphDataSouce ds, String name) {
TimeSeries timeSeries = new TimeSeries(name, timeClass);
timeSeries.setMaximumItemCount(maxSimpleCount);
timeSeries.setMaximumItemAge(maxSimpleAge);
timeSeriesCollection.addSeries(timeSeries);
tss.put(ds, timeSeries);
}

public static void main(String[] args) {
JFrame frame = new JFrame("Test Chart");
final RealTimeGraphPanel rtgp = new RealTimeGraphPanel(Second.class, "Triangle Functions", "Time", "Value");
rtgp.addTimeSeries(new RealTimeGraphDataSouce() {

int i;

public Number getDate() {
return Math.sin(i++ * 0.01);
}
}, "Sin(t)");
rtgp.addTimeSeries(new RealTimeGraphDataSouce() {

int i;

public Number getDate() {
return Math.cos(i++ * 0.01);
}
}, "Cos(t)");
rtgp.addTimeSeries(new RealTimeGraphDataSouce() {

int i;

public Number getDate() {
double d = Math.cos(i * 0.01) + Math.sin(i * 0.01);
i++;
return d;
}
}, "Cos(t)+Sin(t)");
rtgp.addTimeSeries(new RealTimeGraphDataSouce() {

int i;

public Number getDate() {
double d = Math.cosh(i * 0.01);
i++;
return d;
}
}, "cosh(t)");
rtgp.setUpdateRate(20);
rtgp.setTimeClass(Millisecond.class);
frame.getContentPane().add(rtgp, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {

@Override
public void windowClosing(WindowEvent windowevent) {
System.exit(0);
}
});
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
//
private void initComponents() {
bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

buttonGroup1 = new javax.swing.ButtonGroup();
jPanel1 = (chartPanel);
jScrollPane1 = new javax.swing.JScrollPane();
jPanel2 = new javax.swing.JPanel();
jLabel3 = new javax.swing.JLabel();
jSpinner2 = new javax.swing.JSpinner();
jLabel4 = new javax.swing.JLabel();
jLabel1 = new javax.swing.JLabel();
jSpinner1 = new javax.swing.JSpinner();
jLabel2 = new javax.swing.JLabel();
jbtnStart = new javax.swing.JButton();
jbtnStop = new javax.swing.JButton();
jbtnClear = new javax.swing.JButton();
jrdoScaled = new javax.swing.JRadioButton();
jrdoFixed = new javax.swing.JRadioButton();
jLabel6 = new javax.swing.JLabel();
jLabel5 = new javax.swing.JLabel();
jSpinner4 = new javax.swing.JSpinner();
jSpinner3 = new javax.swing.JSpinner();

setName("Form"); // NOI18N

jPanel1.setName("jPanel1"); // NOI18N

javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 460, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 193, Short.MAX_VALUE)
);

jScrollPane1.setBorder(javax.swing.BorderFactory.createTitledBorder("Options"));
jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
jScrollPane1.setName("jScrollPane1"); // NOI18N

jPanel2.setName("jPanel2"); // NOI18N

jLabel3.setText("Update rate:");
jLabel3.setName("jLabel3"); // NOI18N

jSpinner2.setModel(new javax.swing.SpinnerNumberModel(Long.valueOf(0L), Long.valueOf(0L), null, Long.valueOf(50L)));
jSpinner2.setName("jSpinner2"); // NOI18N

org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${updateRate}"), jSpinner2, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);

jLabel4.setText("ms");
jLabel4.setName("jLabel4"); // NOI18N

jLabel1.setText("Range:");
jLabel1.setName("jLabel1"); // NOI18N

binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, jrdoFixed, org.jdesktop.beansbinding.ELProperty.create("${selected}"), jLabel1, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
bindingGroup.addBinding(binding);

jSpinner1.setModel(new javax.swing.SpinnerNumberModel(Long.valueOf(0L), Long.valueOf(0L), null, Long.valueOf(500L)));
jSpinner1.setName("jSpinner1"); // NOI18N

binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${fixedDisplayRange}"), jSpinner1, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);
binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, jrdoFixed, org.jdesktop.beansbinding.ELProperty.create("${selected}"), jSpinner1, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
bindingGroup.addBinding(binding);

jLabel2.setText("ms");
jLabel2.setName("jLabel2"); // NOI18N

binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, jrdoFixed, org.jdesktop.beansbinding.ELProperty.create("${selected}"), jLabel2, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
bindingGroup.addBinding(binding);

jbtnStart.setText("Start");
jbtnStart.setName("jbtnStart"); // NOI18N
jbtnStart.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnStartActionPerformed(evt);
}
});

jbtnStop.setText("Stop");
jbtnStop.setEnabled(false);
jbtnStop.setName("jbtnStop"); // NOI18N
jbtnStop.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnStopActionPerformed(evt);
}
});

jbtnClear.setText("Clear");
jbtnClear.setName("jbtnClear"); // NOI18N

binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, jbtnStop, org.jdesktop.beansbinding.ELProperty.create("${enabled}"), jbtnClear, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
bindingGroup.addBinding(binding);

jbtnClear.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnClearActionPerformed(evt);
}
});

buttonGroup1.add(jrdoScaled);
jrdoScaled.setSelected(true);
jrdoScaled.setText("Scaled");
jrdoScaled.setName("jrdoScaled"); // NOI18N
jrdoScaled.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jrdoScaledActionPerformed(evt);
}
});

buttonGroup1.add(jrdoFixed);
jrdoFixed.setText("Fixed");
jrdoFixed.setName("jrdoFixed"); // NOI18N
jrdoFixed.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jrdoFixedActionPerformed(evt);
}
});

jLabel6.setText("MSA");
jLabel6.setToolTipText("Maxium Simple Time (ms)");
jLabel6.setName("jLabel6"); // NOI18N

jLabel5.setText("MSC");
jLabel5.setToolTipText("Maxium Simple Count");
jLabel5.setName("jLabel5"); // NOI18N

jSpinner4.setModel(new javax.swing.SpinnerNumberModel(Long.valueOf(0L), null, null, Long.valueOf(1L)));
jSpinner4.setName("jSpinner4"); // NOI18N

binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${maxSimpleAge}"), jSpinner4, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);

jSpinner3.setModel(new javax.swing.SpinnerNumberModel());
jSpinner3.setName("jSpinner3"); // NOI18N

binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${maxSimpleCount}"), jSpinner3, org.jdesktop.beansbinding.BeanProperty.create("value"));
bindingGroup.addBinding(binding);

javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
jPanel2.setLayout(jPanel2Layout);
jPanel2Layout.setHorizontalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel2Layout.createSequentialGroup()
.addComponent(jLabel3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSpinner2, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel4)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSpinner1, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel2))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel2Layout.createSequentialGroup()
.addComponent(jbtnStart)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jbtnStop)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jbtnClear)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jrdoScaled)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jrdoFixed)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(jLabel6, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel5, javax.swing.GroupLayout.Alignment.LEADING))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(jSpinner4)
.addComponent(jSpinner3, javax.swing.GroupLayout.DEFAULT_SIZE, 73, Short.MAX_VALUE))
.addContainerGap(13, Short.MAX_VALUE))
);
jPanel2Layout.setVerticalGroup(
jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel2Layout.createSequentialGroup()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jbtnStart)
.addComponent(jbtnStop)
.addComponent(jbtnClear)
.addComponent(jrdoFixed)
.addComponent(jrdoScaled))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel3)
.addComponent(jSpinner2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel4)
.addComponent(jLabel1)
.addComponent(jSpinner1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel2)))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(jLabel5)
.addComponent(jSpinner3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel6)
.addComponent(jSpinner4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addContainerGap())
);

jScrollPane1.setViewportView(jPanel2);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 460, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
);

bindingGroup.bind();
}//


class RefThread extends StopableThread {

@Override
protected void loop() throws InterruptedException {
LinkedHashMap lhm = new LinkedHashMap(tss);
for (RealTimeGraphDataSouce ds : tss.keySet()) {
try {
Number val = ds.getDate();
TimeSeries ts = lhm.get(ds);
ts.addOrUpdate((RegularTimePeriod) timeClass.newInstance(), val);
} catch (Exception ex) {
Logger.getLogger(RealTimeGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
Thread.sleep(updateRate);
}
}
RefThread t1;

public synchronized void start() {
t1 = new RefThread();
t1.start();
jbtnStart.setEnabled(false);
jbtnStop.setEnabled(true);
}

public synchronized void stop() {
t1.exit();
t1 = null;
jbtnStart.setEnabled(true);
jbtnStop.setEnabled(false);
}

public synchronized void clear() {
Collection t = new ArrayList(this.tss.values());
for (TimeSeries timeSeries : t) {
timeSeries.clear();
}
}
private void jbtnStartActionPerformed(java.awt.event.ActionEvent evt) {
start();
}

private void jbtnClearActionPerformed(java.awt.event.ActionEvent evt) {
clear();
}

private void jrdoFixedActionPerformed(java.awt.event.ActionEvent evt) {
xyplot.getDomainAxis().setFixedAutoRange(fixedDisplayRange);
}

private void jrdoScaledActionPerformed(java.awt.event.ActionEvent evt) {
xyplot.getDomainAxis().setFixedAutoRange(0);
}

private void jbtnStopActionPerformed(java.awt.event.ActionEvent evt) {
stop();
}
// Variables declaration - do not modify
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JLabel jLabel5;
private javax.swing.JLabel jLabel6;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JSpinner jSpinner1;
private javax.swing.JSpinner jSpinner2;
private javax.swing.JSpinner jSpinner3;
private javax.swing.JSpinner jSpinner4;
private javax.swing.JButton jbtnClear;
private javax.swing.JButton jbtnStart;
private javax.swing.JButton jbtnStop;
private javax.swing.JRadioButton jrdoFixed;
private javax.swing.JRadioButton jrdoScaled;
private org.jdesktop.beansbinding.BindingGroup bindingGroup;
// End of variables declaration
}

社论:某熊答记者问

几天前的事情了……不过一直登不上Blogger,所以今天才发。

darth ssword 00:30:40
您现在程序的规模大致是多少呢


IcyBear 00:31:40
当前模块大概300row
当前项目大概数K
整个系统应该上数W

darth ssword 00:32:12
天那
您是怎么做到的


IcyBear 00:33:09
一个字:磨
两个字:死抗



darth ssword 00:33:40
经典!
darth ssword 00:33:55
开发周期呢


IcyBear 00:35:24
别提了,八年了……


darth ssword 00:35:45
!!


IcyBear 00:36:02
整个东西就两个人,那个不用java- -
但是超过3/4是java实现- -


darth ssword 00:37:32
究竟是什么让您爆发出如此非凡的勇气和毅力?
darth ssword 00:37:58
什么系统丫


IcyBear 00:38:22
给学校写的网络控制系统,收费的

IcyBear 00:38:45
darth ssword 00:37:32
究竟是什么让您爆发出如此非凡的勇气和毅力?
因为据说有可能不一定会给¥¥


darth ssword 00:40:12
惊,我听说lieo骗到过3000+
darth ssword 00:40:25
您究竟。。。


IcyBear 00:41:15
ToT
国家三令五申,严禁拖欠程序员工资,但是学校竟然,他竟然……(晕过去,饿的)



darth ssword 00:42:02
同情+悲愤
darth ssword 00:43:05
控制如此巨大的项目,您一个人有什么经验和教训吗



IcyBear 00:44:00
文档对一个团队来说是重要的,对一个人来说仿佛就成了累赘



darth ssword 00:45:48
您是否认为您的程序中包含大量的设计模式


IcyBear 00:47:29
有关这个问题,我想这么回答:该用的用了,不该用的乱用了,需要用的地方想用但是不会用,不需要用的地方想不用但是不用就没发写了



darth ssword 00:48:57
您怎么看待uml


IcyBear 00:49:22
没用过……不知道,请下一位记者提问


darth ssword 00:50:02
您对版本控制有什么心得吗


IcyBear 00:50:42
有……有事没事经常commit一下绝对没坏处



darth ssword 00:51:40
在漫长的开发过程中,您是如何抗拒外来的诱惑的


IcyBear 00:52:26
诱惑?要是有诱惑我早TMD不干了(拍桌子)


darth ssword 00:54:34
那么,您除了编程之外的生活是如何度过的?例如学习啊,小妹啊,etc


IcyBear 00:56:51
我用几句名言回答您的提问:
1)六十分万岁,多一份浪费,少一分白费
2)我对3次元空间的MM不感兴趣,如果你们当中有宇宙人,未来人,超能力者,请来找我,以上。
谢谢


darth ssword 00:59:26
谢谢您的回答,您的回答让我很受启迪!


IcyBear 00:59:49
不用感谢,这次的记者招待会就到这里,大家晚安


darth ssword 01:00:27
(掌声)

2008年10月1日星期三

JFreeChart的实时曲线图的例子

好久没更新过技术相关的东西了,今天要开始写管理控制台,里面需要用到实时曲线图,决定使用JFreeChart做,这东西还真的挺好用,简单的几句代码就能搭建一个看起来不错的程序:-)
预览图:



/*
* RealTimeGraphPanel.java
*
* Created on 2008年10月1日, 下午2:04
*/
package cn.bearice.ipcontroller.manager.graph;

import cn.bearice.java.util.StopableThread;
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;

/**
*
* @author Bearice
*/
public class RealTimeGraphPanel extends javax.swing.JPanel {

private static final long serialVersionUID = 8250077948583513551L;
TimeSeriesCollection tcl;
ChartPanel cp;
JFreeChart jfc;
ArrayList tss = new ArrayList();
TimeSeries tts = new TimeSeries("Avg.", Second.class);

/** Creates new form RealTimeGraphPanel */
public RealTimeGraphPanel() {
tcl = new TimeSeriesCollection();
tcl.addSeries(tts);
addTimeSeries();
jfc = ChartFactory.createTimeSeriesChart("Random Numbers", "Time", "Value", tcl, true, true, false);
XYPlot xyplot = jfc.getXYPlot();
ValueAxis valueaxis = xyplot.getDomainAxis();
valueaxis.setAutoRange(true);
// valueaxis.setInverted(true);
valueaxis = xyplot.getRangeAxis();
valueaxis.setAutoRange(true);
cp = new ChartPanel(jfc);
initComponents();
}

public void addTimeSeries() {
TimeSeries timeSeries = new TimeSeries("Random" + tss.size(), Second.class);
tcl.addSeries(timeSeries);
tss.add(timeSeries);
}

public static void main(String[] args) {
JFrame frame = new JFrame("Test Chart");
final RealTimeGraphPanel rtgp = new RealTimeGraphPanel();
frame.getContentPane().add(rtgp, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);

frame.addWindowListener(new WindowAdapter() {

@Override
public void windowClosing(WindowEvent windowevent) {
System.exit(0);
}
});
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
//
private void initComponents() {

jbtnStartStop = new javax.swing.JButton();
jPanel1 = (cp);
jbtnFixed = new javax.swing.JButton();
jbtnScaled = new javax.swing.JButton();
jbtnClear = new javax.swing.JButton();
jbtnAdd = new javax.swing.JButton();

setName("Form"); // NOI18N

jbtnStartStop.setText("Start");
jbtnStartStop.setName("jbtnStartStop"); // NOI18N
jbtnStartStop.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnStartStopActionPerformed(evt);
}
});

jPanel1.setName("jPanel1"); // NOI18N

javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 261, Short.MAX_VALUE)
);

jbtnFixed.setText("Fixed");
jbtnFixed.setName("jbtnFixed"); // NOI18N
jbtnFixed.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnFixedActionPerformed(evt);
}
});

jbtnScaled.setText("Scaled");
jbtnScaled.setName("jbtnScaled"); // NOI18N
jbtnScaled.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnScaledActionPerformed(evt);
}
});

jbtnClear.setText("Clear");
jbtnClear.setName("jbtnClear"); // NOI18N
jbtnClear.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnClearActionPerformed(evt);
}
});

jbtnAdd.setText("Add");
jbtnAdd.setName("jbtnAdd"); // NOI18N
jbtnAdd.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtnAddActionPerformed(evt);
}
});

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jbtnStartStop)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jbtnFixed)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jbtnScaled)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jbtnClear)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jbtnAdd)
.addContainerGap(53, Short.MAX_VALUE))
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jbtnStartStop)
.addComponent(jbtnFixed)
.addComponent(jbtnScaled)
.addComponent(jbtnClear)
.addComponent(jbtnAdd))
.addContainerGap())
);
}//


class T1 extends StopableThread {

@Override
protected void loop() throws InterruptedException {
for (TimeSeries timeSeries : tss) {
double d = randomNum();
num = (num + d) / 2;
timeSeries.add(new Second(), d);
}
tts.add(new Second(), num);
Thread.sleep(1000);
}
double num;
Random rand = new Random();

private double randomNum() {
return rand.nextGaussian();
}
}
T1 t1;
private void jbtnStartStopActionPerformed(java.awt.event.ActionEvent evt) {
if (t1 == null) {
t1 = new T1();
t1.start();
jbtnStartStop.setText("stop");
} else {
t1.exit();
t1 = null;
jbtnStartStop.setText("start");
}
}

private void jbtnFixedActionPerformed(java.awt.event.ActionEvent evt) {
// cp.setAutoscrolls(true);
XYPlot xyplot = jfc.getXYPlot();
ValueAxis valueaxis = xyplot.getDomainAxis();
valueaxis.setFixedAutoRange(50000);
}

private void jbtnScaledActionPerformed(java.awt.event.ActionEvent evt) {
XYPlot xyplot = jfc.getXYPlot();
ValueAxis valueaxis = xyplot.getDomainAxis();
valueaxis.setFixedAutoRange(0);
}

private void jbtnClearActionPerformed(java.awt.event.ActionEvent evt) {
for (TimeSeries timeSeries : tss) {
timeSeries.clear();
}
}

private void jbtnAddActionPerformed(java.awt.event.ActionEvent evt) {
addTimeSeries();
}
// Variables declaration - do not modify
private javax.swing.JPanel jPanel1;
private javax.swing.JButton jbtnAdd;
private javax.swing.JButton jbtnClear;
private javax.swing.JButton jbtnFixed;
private javax.swing.JButton jbtnScaled;
private javax.swing.JButton jbtnStartStop;
// End of variables declaration
}

PS:里面用到了一个自己实现的StopableThread,代码如下:

/*
* Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
* Release under GNU/GPL Version 2.
*/
package cn.bearice.java.util;

/**
* 可以停止的线程。
* @author Bearice
*/
public abstract class StopableThread extends Thread {

protected boolean exit = false;

/**
* 线程开始后,进入循环前调用。
*/
protected void before() {
//System.out.println("Starting thread: "+this);
}

/**
* 线程退出前,循环退出后调用。
*/
protected void after() {
// System.out.println("Ending thread: "+this);
}

/**
* 循环体代码。
* @throws java.lang.InterruptedException
*/
protected abstract void loop() throws InterruptedException;

/**
* 指示线程退出循环。
*/
public synchronized void exit() {
exit = true;
interrupt();
}

@Override
public final void run() {
before();
while (!exit) {
try {
loop();
} catch (InterruptedException ex) {
}
}
after();
}
}