自定义事件和事件监听器。。。

本文介绍了一种在CSCW系统中实现线程间通信的方法,通过自定义事件机制代替共享内存区,解决了多线程间的数据同步问题。具体实现包括自定义事件类MyDocumentEvent及监听接口MyDocumentListener。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题是这样来的:

       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();
     }
}


代码上都有详细的注释。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值