「java监听队列对象」java怎么实现事件监听

博主:adminadmin 2022-12-09 11:27:06 106

今天给各位分享java监听队列对象的知识,其中也会对java怎么实现事件监听进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

java设计模式-回调、事件监听器、观察者模式

转自( )

背景

关于设计模式,之前笔者写过工厂模式,最近在使用gava ListenableFuture时发现事件监听模型特别有意思,于是就把事件监听、观察者之间比较了一番,发现这是一个非常重要的设计模式,在很多框架里扮演关键的作用。

回调函数

为什么首先会讲回调函数呢?因为这个是理解监听器、观察者模式的关键。

什么是回调函数

所谓的回调,用于回调的函数。 回调函数只是一个功能片段,由用户按照回调函数调用约定来实现的一个函数。 有这么一句通俗的定义:就是程序员A写了一段程序(程序a),其中预留有回调函数接口,并封装好了该程序。程序员B要让a调用自己的程序b中的一个方法,于是,他通过a中的接口回调自己b中的方法。

举个例子:

这里有两个实体:回调抽象接口、回调者(即程序a)

回调接口(ICallBack )

public interface ICallBack {

public void callBack();

}

回调者(用于调用回调函数的类)

public class Caller {

}

回调测试:

public static void main(String[] args) {

Caller call = new Caller();

call.call(new ICallBack(){

控制台输出:

start...

终于回调成功了!

end...

还有一种写法

或实现这个ICallBack接口类

class CallBackC implements ICallBack{

@Override

public void callBack() {

System.out.println("终于回调成功了!");

}

}

有没有发现这个模型和执行一个线程,Thread很像。 没错,Thread就是回调者,Runnable就是一个回调接口。

new Thread(new Runnable(){

@Override

public void run() {

System.out.println("回调一个新线程!");

}}).start();

Callable也是一个回调接口,原来一直在用。 接下来我们开始讲事件监听器

事件监听模式

什么是事件监听器

监听器将监听自己感兴趣的事件一旦该事件被触发或改变,立即得到通知,做出响应。例如:android程序中的Button事件。

java的事件监听机制可概括为3点:

java的事件监听机制涉及到 事件源,事件监听器,事件对象 三个组件,监听器一般是接口,用来约定调用方式

当事件源对象上发生操作时,它将会调用事件监听器的一个方法,并在调用该方法时传递事件对象过去

事件监听器实现类,通常是由开发人员编写,开发人员通过事件对象拿到事件源,从而对事件源上的操作进行处理

举个例子

这里我为了方便,直接使用jdk,EventListener 监听器,感兴趣的可以去研究下源码,非常简单。

监听器接口

public interface EventListener extends java.util.EventListener {

//事件处理

public void handleEvent(EventObject event);

}

事件对象

public class EventObject extends java.util.EventObject{

private static final long serialVersionUID = 1L;

public EventObject(Object source){

super(source);

}

public void doEvent(){

System.out.println("通知一个事件源 source :"+ this.getSource());

}

}

事件源

事件源是事件对象的入口,包含监听器的注册、撤销、通知

public class EventSource {

//监听器列表,监听器的注册则加入此列表

private VectorEventListener ListenerList = new VectorEventListener();

//注册监听器

public void addListener(EventListener eventListener){

ListenerList.add(eventListener);

}

//撤销注册

public void removeListener(EventListener eventListener){

ListenerList.remove(eventListener);

}

//接受外部事件

public void notifyListenerEvents(EventObject event){

for(EventListener eventListener:ListenerList){

eventListener.handleEvent(event);

}

}

}

测试执行

public static void main(String[] args) {

EventSource eventSource = new EventSource();

}

控制台显示:

通知一个事件源 source :openWindows

通知一个事件源 source :openWindows

doOpen something...

到这里你应该非常清楚的了解,什么是事件监听器模式了吧。 那么哪里是回调接口,哪里是回调者,对!EventListener是一个回调接口类,handleEvent是一个回调函数接口,通过回调模型,EventSource 事件源便可回调具体监听器动作。

有了了解后,这里还可以做一些变动。 对特定的事件提供特定的关注方法和事件触发

public class EventSource {

...

public void onCloseWindows(EventListener eventListener){

System.out.println("关注关闭窗口事件");

ListenerList.add(eventListener);

}

}

public static void main(String[] args) {

EventSource windows = new EventSource();

/**

* 另一种实现方式

*/

//关注关闭事件,实现回调接口

windows.onCloseWindows(new EventListener(){

}

这种就类似于,我们的窗口程序,Button监听器了。我们还可以为单击、双击事件定制监听器。

观察者模式

什么是观察者模式

观察者模式其实原理和监听器是一样的,使用的关键在搞清楚什么是观察者、什么是被观察者。

观察者(Observer)相当于事件监器。有个微博模型比较好理解,A用户关注B用户,则A是B的观察者,B是一个被观察者,一旦B发表任何言论,A便可以获得。

被观察者(Observable)相当于事件源和事件,执行事件源通知逻辑时,将会回调observer的回调方法update。

举个例子

为了方便,同样我直接使用jdk自带的Observer。

一个观察者

public class WatcherDemo implements Observer {

@Override

public void update(Observable o, Object arg) {

if(arg.toString().equals("openWindows")){

System.out.println("已经打开窗口");

}

}

}

被观察者

Observable 是jdk自带的被观察者,具体可以自行看源码和之前的监听器事件源类似。

主要方法有

addObserver() 添加观察者,与监听器模式类似

notifyObservers() 通知所有观察者

类Watched.java的实现描述:被观察者,相当于事件监听的事件源和事件对象。又理解为订阅的对象 主要职责:注册/撤销观察者(监听器),接收主题对象(事件对象)传递给观察者(监听器),具体由感兴趣的观察者(监听器)执行

/**

}

测试执行

public static void main(String[] args) {

Watched watched = new Watched();

WatcherDemo watcherDemo = new WatcherDemo();

watched.addObserver(watcherDemo);

watched.addObserver(new Observer(){

@Override

public void update(Observable o, Object arg) {

if(arg.toString().equals("closeWindows")){

System.out.println("已经关闭窗口");

}

}

});

//触发打开窗口事件,通知观察者

watched.notifyObservers("openWindows");

//触发关闭窗口事件,通知观察者

watched.notifyObservers("closeWindows");

控制台输出:

已经打开窗口

已经关闭窗口

总结

从整个实现和调用过程来看,观察者和监听器模式基本一样。

有兴趣的你可以基于这个模型,实现一个简单微博加关注和取消的功能。 说到底,就是事件驱动模型,将调用者和被调用者通过一个链表、回调函数来解耦掉,相互独立。

“你别来找我,有了我会找你”。

整个设计模式的初衷也就是要做到低耦合,低依赖。

再延伸下,消息中间件是什么一个模型? 将生产者+服务中心(事件源)和消费者(监听器)通过消息队列解耦掉. 消息这相当于具体的事件对象,只是存储在一个队列里(有消峰填谷的作用),服务中心回调消费者接口通过拉或取的模型响应。 想必基于这个模型,实现一个简单的消息中间件也是可以的。

还比如gava ListenableFuture,采用监听器模式就解决了future.get()一直阻塞等待返回结果的问题。

有兴趣的同学,可以再思考下观察者和责任链之间的关系, 我是这样看的。

同样会存在一个链表,被观察者会通知所有观察者,观察者自行处理,观察者之间互不影响。 而责任链,讲究的是击鼓传花,也就是每一个节点只需记录继任节点,由当前节点决定是否往下传。 常用于工作流,过滤器web filter。

Java:Object的监视器模型上,一个对象拥有一个同步队列和等待队列是什么意思?

深入理解wait/notify/notifyAll的作用

notify: 唤醒在监视器对象上等待的单个线程,此时调用该方法的代码继续执行。

notifyAll: 唤醒在监视器对象上等待的所有线程,此时调用该方法的代码继续执行。

第一、为什么会有wait/notify/notifyAll这几个方法?

(1) wait/notify/notifyAll是为了避免轮询(尝试执行)带来的性能损失,这句话是什么意思?看下面的讲解:

为了说清道理,我们用“图书馆借书”这个经典例子来作解释。

在简单的synchrnozed 同步机制下,李四如果想借,先要去图书馆查看书有没有还回来。

李四是个心急的人,他每天都去图书馆查;而张三看书看得慢,过了半个月才把书还回来,

结果李四在这半个月里全都白跑了,浪费了不少交通车费。

而如果使用wait/notify机制,李四就不用白忙了。

他第一次去图书馆时发现书已借走,就回家静静等待(wait);

张三把书还掉后,通知(notify)李四,李四去图书馆拿书即可。整个过程中,李四没有白跑,没浪费钱。

书 ---- 临界资源,需互斥地访问

张三,李四 ---- 两个竞争的线程

坐车去图书馆查书 ---- 轮询

车费 ---- CPU空间

等待 ---- wait

通知下一个借书者 ---- notify

也就是说,若使用简单的synchonized机制实现互斥,会导致线程主动发起轮询,若N次轮询没有成功,就产生了N次的CPU空间浪费;

如果加上了 wait/notify机制,就可以避免这些无谓的轮询,节省CPU的消耗。

(2) wait/notify/notifyAll可以控制线程执行与不执行。

第二、为什么wait/notify/notifyAll方法一定要写在synchronized里面呢?

因为第一点已经说了wait/notify/notifyAll的作用是为了避免轮询带来的性能损失,

而产生轮询的条件是多个线程对同一个资源进行操作。

第三、为什么wait/notify/notifyAll方法定义在Object类里面呢?

因为wait/notify/notifyAll必须写在synchronized里面,而synchronized的对象锁可以是任意对象,

所以wait/notify/notifyAll方法定义在Object类里面呢。

调用wait/notify/notifyAll方法的对象,必须和synchronized()的对象锁一致。

第四、

看一个wait和notify示例:

// 这个示例是不需要flag标记的:

public class Resource {

public String name;

public String sex;

public boolean flag = true;

public static void main(String[] args) {

Resource r = new Resource();

Input in = new Input(r);

Thread t1 = new Thread(in);

Output out = new Output(r);

Thread t2 = new Thread(out);

t1.start();

t2.start();

}

}

class Input implements Runnable {

Resource r;

public Input(Resource r) {

this.r = r;

}

public void run() {

int x = 0;

while (true) {

synchronized (r) {

try {

Thread.sleep(1000);

} catch (InterruptedException e1) {

e1.printStackTrace();

}

if (x == 0) {

r.name = "谢霆锋";

r.sex = "男人";

} else {

r.name = "张柏芝";

r.sex = "女人";

}

// 注意:调用notify方法后,唤醒了等待的线程。

// 但这里代码继续执行,并不是马上交给其它线程执行,除非cpu时间片结束。

r.notify();

try {

r.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

x = (x + 1) % 2;

}

}

}

class Output implements Runnable {

Resource r;

public Output(Resource r) {

this.r = r;

}

public void run() {

while (true) {

synchronized (r) {

System.out.println("--------------" + r.name + "是" + r.sex);

r.notify();

try {

r.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

--------------------------------------------------------------

这里要注意,再次强调:

wait/notify/notifyAll方法要放在synchronized里面,除此之外,还要非常非常注意一个重点:

调用wait/notify/notifyAll方法的对象,必须要和synchronized的对象锁是一致的。

如,以下代码是错误的:

class MyThread extends Thread {

public static Object obj = new Object();

public void run() {

synchronized(obj) {

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

this.notify();

}

}

}

--------------------------------------------------------------

如何用java实现自动监听处理jsp页面的

一、监听域对象中属性的变更的监听器

域对象中属性的变更的事件监听器就是用来监听 ServletContext, HttpSession, HttpServletRequest 这三个对象中的属性变更信息事件的监听器。  

这三个监听器接口分别是ServletContextAttributeListener, HttpSessionAttributeListener 和ServletRequestAttributeListener,这三个接口中都定义了三个方法来处理被监听对象中的属性的增加,删除和替换的事件,同一个事件在这三个接口中对应的方法名称完全相同,只是接受的参数类型不同。

1.1、attributeAdded 方法

当向被监听对象中增加一个属性时,web容器就调用事件监听器的attributeAdded方法进行响应,这个方法接收一个事件类型的参数,监听器可以通过这个参数来获得正在增加属性的域对象和被保存到域中的属性对象

各个域属性监听器中的完整语法定义为:

public void attributeAdded(ServletContextAttributeEvent scae)

public void attributeReplaced(HttpSessionBindingEvent hsbe)

public void attributeRmoved(ServletRequestAttributeEvent srae)

1.2、attributeRemoved 方法

当删除被监听对象中的一个属性时,web容器调用事件监听器的attributeRemoved方法进行响应

各个域属性监听器中的完整语法定义为:

public void attributeRemoved(ServletContextAttributeEvent scae)

public void attributeRemoved (HttpSessionBindingEvent hsbe)

public void attributeRemoved (ServletRequestAttributeEvent srae)

1.3、attributeReplaced 方法

当监听器的域对象中的某个属性被替换时,web容器调用事件监听器的attributeReplaced方法进行响应

各个域属性监听器中的完整语法定义为:

public void attributeReplaced(ServletContextAttributeEvent scae)

public void attributeReplaced (HttpSessionBindingEvent hsbe)

public void attributeReplaced (ServletRequestAttributeEvent srae)

1.4、ServletContextAttributeListener监听器范例:

编写ServletContextAttributeListener监听器监听ServletContext域对象的属性值变化情况,代码如下:

package me.gacl.web.listener;

import java.text.MessageFormat;

import javax.servlet.ServletContextAttributeEvent;

import javax.servlet.ServletContextAttributeListener;

/**

* @ClassName: MyServletContextAttributeListener

* @Description: ServletContext域对象中属性的变更的事件监听器

* @author: 孤傲苍狼

* @date: 2014-9-11 下午10:53:04

*

*/

public class MyServletContextAttributeListener implements

ServletContextAttributeListener {

@Override

public void attributeAdded(ServletContextAttributeEvent scab) {

String str =MessageFormat.format(

"ServletContext域对象中添加了属性:{0},属性值是:{1}"

,scab.getName()

,scab.getValue());

System.out.println(str);

}

@Override

public void attributeRemoved(ServletContextAttributeEvent scab) {

String str =MessageFormat.format(

"ServletContext域对象中删除属性:{0},属性值是:{1}"

,scab.getName()

,scab.getValue());

System.out.println(str);

}

@Override

public void attributeReplaced(ServletContextAttributeEvent scab) {

String str =MessageFormat.format(

"ServletContext域对象中替换了属性:{0}的值"

,scab.getName());

System.out.println(str);

}

}

在web.xml文件中注册监听器

listener

descriptionMyServletContextAttributeListener监听器/description

listener-classme.gacl.web.listener.MyServletContextAttributeListener/listener-class

/listener

编写ServletContextAttributeListenerTest.jsp测试页面

%@ page language="java" pageEncoding="UTF-8"%

!DOCTYPE HTML

html

head

titleServletContextAttributeListener监听器测试/title

/head

body

%

//往application域对象中添加属性

application.setAttribute("name", "孤傲苍狼");

//替换application域对象中name属性的值

application.setAttribute("name", "gacl");

//移除application域对象中name属性

application.removeAttribute("name");

%

/body

/html

运行结果如下:

从运行结果中可以看到,ServletContextListener监听器成功监听到了ServletContext域对象(application)中的属性值的变化情况。

java监听队列对象的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于java怎么实现事件监听、java监听队列对象的信息别忘了在本站进行查找喔。

The End

发布于:2022-12-09,除非注明,否则均为首码项目网原创文章,转载请注明出处。