问题是这样来的:
CSCW系统一致性算法的问题,必须实现所有客户端在服务器上对应的各个线程之间能进行通信,管道的方法是行不通,我的导师的指导说可以通过共享区的方法来实现各个线程的通信,比如把要传递给其他线程的消息放在某个共享区,然后其他的线程到这个共享区来读取。问题是,这个所有线程都会对这个共享区 进行读/写操作,而且当一个线程往这个共享区里写入一个对象时,又必须保证其他的所有的线程都已经读到了这个对象后,这个共享区的对象才能再次被改变,别的线程才能往里面写东西,这设计到生产者和消费者的问题,实现起来也是相当复杂,因为这个共享区的信息读取是非常频繁的。最后在我同学刘少林建议我通过自定义事件来实现,我通过网上找资料,查看JTextArea、DocumentEvent、AbstractDocument.DefaultDocumentEvent的源码,最后终于搞定了。。。实现如下:
事件的组成
如果想要自定义一个事件,则必须提供一个事件的监听接口以及一个事件类。在JAVA中监听接口继承java.util.EventListener,事件类继承java.util.EventObject.
下面是我自定义的事件类:MyDocumentEvent.java
package server;
import java.util.EventObject;
import javax.swing.*;
public class MyDocumentEvent extends EventObject {
private JTextArea jTextArea;//共享区
private long id;//标识字段
private int offset;//起始位置
private int length;//长度,用来标识插入的String的长度或删除的String的长度
private String type;//“insert”,"remove"
public MyDocumentEvent(int offs, int len, long id, JTextArea jTextArea,String type) {
super(jTextArea);
this.jTextArea = jTextArea;
this.offset=offs;
this.length=len;
this.id = id;
this.type=type;
}
public Object getSource() {
return jTextArea;
}
public void getMsg(){
System.out.println("这个是由 "+id+" 执行的操作。。。");
}
public int getOffset() {//得到起始的位置
return offset;
}
public int getLength() {//得到长度
return length;
}
public long getId() {//得到标识
return id;
}
}
下面是自定义的监听接口
package server;
import java.util.EventListener;
public interface MyDocumentListener extends EventListener{
public void insertUpdate(MyDocumentEvent event);//当JTextArea即共享区进行insert操作时就执行
public void removeUpdate(MyDocumentEvent event);//当JTextArea即共享区进行remove操作时就执行
}
下面是共享区JTextAreaSource.java的代码,继承JTextArea
package server;
import javax.swing.*;
import java.util.*;
class JTextAreaSource extends JTextArea {
public JTextAreaSource() {
super();
}
//注册监听器,如果这里没有使用Vector而是使用ArrayList的话,要注意同步问题
public void addMyDocumentListener(MyDocumentListener dl) {
repository.addElement(dl); //这步要注意同步问题
}
//如果这里没有使用Vector而是使用ArrayList的话,要注意同步问题
public void notifyDocumentInsertUpdate(MyDocumentEvent event) {
Enumeration enum1 = repository.elements(); //这步要注意同步问题
while (enum1.hasMoreElements()) {
dl = (MyDocumentListener) enum1.nextElement();
dl.insertUpdate(event);//当进行insert操作,就调用用户的insertUpdate()方法
}
}
public void notifyDocumentRemoveUpdate(MyDocumentEvent event) {
Enumeration enum1 = repository.elements(); //这步要注意同步问题
while (enum1.hasMoreElements()) {
dl = (MyDocumentListener) enum1.nextElement();
dl.removeUpdate(event);当进行remove操作,就调用用户的removeUpdate()方法
}
}
//删除监听器,如果这里没有使用Vector而是使用ArrayList那么要注意同步问题
public void removeDemoListener(MyDocumentListener dl) {
repository.remove(dl); //这步要注意同步问题
}
public synchronized void insert(int offs,String str,long id) {
this.insert(str,offs);
//id就是用户的标识
notifyDocumentInsertUpdate(new MyDocumentEvent(offs,str.length(),id,this,"insert"));
}
public synchronized void remove(int offs ,int end,long id) {
this.replaceRange("",offs,end);
notifyDocumentRemoveUpdate(new MyDocumentEvent(offs,end-offs,id,this,"remove"));
}
private Vector repository = new Vector();//用来存储所有的监听者
private MyDocumentListener dl;
private long id;//用户标识
private int offset;
private int length;
}
下面是测试的代码Test.java
package server;
import java.lang.Thread;
public class Test implements MyDocumentListener {
private JTextAreaSource jt;
public Test()
{
jt=new JTextAreaSource();
jt.addMyDocumentListener(this);
System.out.println("添加监听器完毕");
try {
Thread.sleep(3000);
//在0位置插入"我是谁。。。。",并把自己的标识2202008传过去
jt.insert(0,"我是谁。。。。",2202008);
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
//jt.addMyDocumentListener(this);
System.out.println("添加监听器完毕2");
try {
Thread.sleep(3000);
//删除0位置后的两个字符,并把自己的标识2202008传过去
jt.remove(0,2,2202008);
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
//jt.addMyDocumentListener(this);
System.out.println("添加监听器完毕3");
try {
Thread.sleep(3000);
//在位置5插入"实现了自定义事件",并把自己的标识2202008传过去
jt.insert(5,"实现了自定义事件",2202008);
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
public static void main(String args[])
{
new Test();
}
//下面的方法,就是监听接口中的方法,有共享区调用
public void insertUpdate(MyDocumentEvent event){
event.getMsg();
System.out.println("在位置"+event.getOffset()+"处插入长度为"+event.getLength()+"的字符");
System.out.println("文本的内容为"+jt.getText());
System.out.println();
}
public void removeUpdate(MyDocumentEvent event){
event.getMsg();
System.out.println("在位置"+event.getOffset()+"删除长度为"+event.getLength()+"的字符");
System.out.println("文本的内容为"+jt.getText());
System.out.println();
}
}
代码上都有详细的注释。。。。