建立 Bean 時必須假定它在多執行緒環境運行:
getCircleSize())或「微小」(執行代碼極少,執行期間物件狀態不變)。建議:所有 public 方法設 synchronized,僅在確保必要且有差異時移除//: BangBean2.java
public class BangBean2 extends Canvas implements Serializable {
private int xm, ym;
private int cSize = 20;
private String text = "Bang!";
private int fontSize = 48;
private Color tColor = Color.red;
private Vector actionListeners = new Vector(); // 支援多播
public BangBean2() {
addMouseListener(new ML());
addMouseMotionListener(new MM());
}
// 所有 getter/setter 同步
public synchronized int getCircleSize() { return cSize; }
public synchronized void setCircleSize(int newSize) { cSize = newSize; }
// ... 其他屬性同步存取器 ...
public void paint(Graphics g) {
g.setColor(Color.black);
g.drawOval(xm - cSize/2, ym - cSize/2, cSize, cSize);
}
// 多播監聽器管理:同步
public synchronized void addActionListener(ActionListener l) { actionListeners.addElement(l); }
public synchronized void removeActionListener(ActionListener l) { actionListeners.removeElement(l); }
// 通知監聽器:故意不加 synchronized
public void notifyListeners() {
ActionEvent a = new ActionEvent(BangBean2.this, ActionEvent.ACTION_PERFORMED, null);
Vector lv = null;
synchronized(this) { lv = (Vector)actionListeners.clone(); } // 克隆快照
for(int i = 0; i < lv.size(); i++) {
ActionListener al = (ActionListener)lv.elementAt(i);
al.actionPerformed(a);
}
}
class ML extends MouseAdapter {
public void mousePressed(MouseEvent e) {
Graphics g = getGraphics();
g.setColor(tColor);
g.setFont(new Font("TimesRoman", Font.BOLD, fontSize));
int width = g.getFontMetrics().stringWidth(text);
g.drawString(text, (getSize().width - width) /2, getSize().height/2);
g.dispose();
notifyListeners();
}
}
class MM extends MouseMotionAdapter {
public void mouseMoved(MouseEvent e) { xm = e.getX(); ym = e.getY(); repaint(); }
}
// 測試主程式...
} ///:~
actionListenersclone() 向量**,對克隆體迭代 → 原向量可安全操作paint() 不修改cSize 由同步方法修改,paint() 用到 → 應同步。但問:**最壞情況是什麼?** 僅暫時效果 → 保持不同步避免開銷Canvas.paint() 不同步(僅作線索,synchronized 不可繼承)在 main() 中添加三個 ActionListener,演示多播事件分發。