亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

JMX Notification Model

系統 1585 0

? Since Notification Model is actually a typical?observer model, I will start with the observer model, and evolve it to the Notification Model in JMX.

?

? Simply, the observer pattern allows one object (the observer) to watch another object ( the subject), actually the observer and the subject form the publish-subscribe relationship. And through this pattern, the subject can register and unregister the observer, and when event of some type occurs, subject can also inform the corresponding observer of an occuring event. And from the?following picture, we can see that?observer pattern consist of a publisher, a listener and a event.


JMX Notification Model
?Ok, after we have checked the big picture of Observer pattern,?I would like to show you an simple concreate example of observer pattern.

?

    public interface IPublisher {

	public void register(IListener li);
	
	public void unregister(IListener li);
	
	public void notifyEvent(IEvent event);
}


public interface IListener {
	public void handleEvent(IEvent event);
}

public interface IEvent {
	public void setSource(Object obj);
	
	public Object getSource();
	
	public void setType(String type);
	
	public String getType();
}
  

?

?? Then our implementation:

??

    public class PublisherImpl implements IPublisher {
	List<IListener> listenerList=new ArrayList<IListener>();
	public void notifyEvent(IEvent event) {
		for(IListener li:listenerList)
			li.handleEvent(event);
	}

	public void register(IListener li) {
		listenerList.add(li);
	}

	public void unregister(IListener li) {
		listenerList.remove(li);
	}
}

public class EventImpl implements IEvent {
	private Object source;
	private String type;
	public Object getSource() {
		return source;
	}

	public String getType() {
		return type;
	}

	public void setSource(Object obj) {
		this.source=obj;
	}

	public void setType(String type) {
		this.type=type;
	}

}


  

?

? Ok, when we done this, we need?to check them:

?

                public static void main(String[] args) {

		IPublisher publisher = new PublisherImpl();

		// add new listener
		publisher.register(new IListener() {
			public void handleEvent(IEvent event) {
				System.out.println(event.getType());
			}
		});
		
		//notify a print event
		publisher.notifyEvent(new EventImpl());
	}

  

???Wow, it is easy, isn't it?

?

??? But?what would happen if we?unregister a listener when the publisher is notifying all the registered listener of?the occurrence of the event. One possible situation is that, the listener has been unregistered, but it is still notified by the publisher. For this situation,?some people would say, use synchronization. Yeah, you got it. Synchronization can solve this problem. Let's modify our existing PublisherImpl:

    public class PublisherImpl implements IPublisher {
	List<IListener> listenerList=new ArrayList<IListener>();
	public synchronized void notifyEvent(IEvent event) {
		for(IListener li:listenerList)
			li.handleEvent(event);
	}

	public synchronized void register(IListener li) {
		listenerList.add(li);
	}

	public synchronized void unregister(IListener li) {
		listenerList.remove(li);
	}
}
  

?

?? Well, things seem fine now, but synchronization brings in some other problems, for instance, thread A is notifying the registered listeners now, and meanwhile thread B and C want to register a listener to the publisher, since these methods are synchronized, thread B and C have to wait until thread A finishes its notifying task. This would causes the performance reduction. After analyzing the problem, we find that why thread B and C have to wait until all the listeners in thread A finish their handling, they dont care about this, what thread B and C do care is to have their listners registered in the publisher, but in order to avoid the first problem we described above, we can just get rid of the synchronization of the notifyEvent() method, but we can minimize the synchronized scope and separate the operations on listnerList from the notifying process. As the below shows:

    public void notifyEvent(IEvent event) {
		// local listnerList,copy from listenerList
		IListener[] listners = null;
		synchronized (this) {
			listners = Arrays.copyOf(listenerList.toArray(new IListener[0]),
					listenerList.size());
		}
		for (IListener li : listners)
			li.handleEvent(event);
	}
  

? But this still can't solve the performance problem, let's think of such a listener registered in the publisher:

?

    public class ListernerImpl implements IListener {
	public void handleEvent(IEvent event) {
		while(true)
		{}
	}
}
  

?

?? This kind of listener would make all the following listeners unaccessible. So the best solution is to?use a Thread pool to handle the notifying process. Since we have Executor that matches our conditions in JDK5.0, we'll use it here. First, we need to expand the IPublisher interface with IExecutorHandler interface, then the IPublisher can have the ability of handling the Executor.

    public interface IExecutorHandler {
	public void setExecutor(Executor executor);
	public Executor getExecutor();
}

public interface IPublisher extends IExecutorHandler {
                ...
}

  

?

??And then implements the IExecutorHandler in PublisherImpl:

    public class PublisherImpl implements IPublisher {
	private Executor executor;
	private Executor defaultExecutor=new Executor(){
		public void execute(Runnable command) {
			//default Executor using caller thread
			command.run();
		}
	};
	
	public Executor getExecutor() {
		return executor!=null?executor:defaultExecutor;
	}

	public void setExecutor(Executor executor) {
		this.executor=executor!=null?executor:defaultExecutor;
	}
                
                // the original code
                ...
	
	}
  

????

??? Since we are using the Executor interface here, it requires a Runnable object for its method. Therefore, we need to wrap our IListener and IEvent as a SendNotifJob for Executor to use.

???

    public class PublisherImpl implements IPublisher {
	...

	public void notifyEvent(IEvent event) {
		// local listnerList,copy from listenerList
		IListener[] listners = null;
		synchronized (this) {
			listners = Arrays.copyOf(listenerList.toArray(new IListener[0]),
					listenerList.size());
		}
		for (IListener li : listners)
			getExecutor().execute(new SendNotifJob(li,event));
	}

	...
	
	private class SendNotifJob implements Runnable
	{
		IListener listener; 
		IEvent event;
		public SendNotifJob(IListener listener,IEvent event)
		{
			this.listener=listener;
			this.event=event;
		}
		public void run() {
			listener.handleEvent(event);
		}
	}
}
  

?

??? Finally, we can set our executor before we notify the listener of the event.

???

                                    ...
		//set executor
		publisher.setExecutor(Executors.newFixedThreadPool(10));
		
		//notify a print event
		publisher.notifyEvent(new EventImpl());
  

?

??? Here we use a thread pool which contains 10 threads as the Executor.

???

??? Well,?everything seems fine now. But?for synchronization in our example, I am wonderring why we?have to?take the publisher instance as a lock, as opposed to the listenerList itself. When we use synchronization, we have to ask ourselves a question, what are we protecting? In our?case, we need to protect?lisenerList in the Publisher instance from being accessed by different threads at the same time, not the publisher instance. Thus, I think we should refactory our code as below:

                    List<IListener> listenerList = new ArrayList<IListener>();

	public void notifyEvent(IEvent event) {
		// local listnerList,copy from listenerList
		IListener[] listners = null;
		synchronized (listenerList ) {
			listners = Arrays.copyOf(listenerList.toArray(new IListener[0]),
					listenerList.size());
		}
		for (IListener li : listners)
			getExecutor().execute(new SendNotifJob(li,event));
	}

	public void register(IListener li) {
                             synchronized (listenerList ) {
		listenerList.add(li);
                             }
	}

	public synchronized void unregister(IListener li) {
	             synchronized (listenerList ) {
		listenerList.remove(li);
                             }
	}

  

?

???And in fact, we dont have to?handle the synchronization of the?listenerList by ourselves, besides that,?no matter when we add a method related to listenerList, we have to repeat the same synchronization code. For instance, if we want to unregister all listeners, we need to add a unregisterAll() method.

??

                    public void unregisterAll()
	{
		synchronized (listenerList) {
			//remove listenerList
		}
	}
  

???

??? If you're familiar with design pattern, you must know strategy pattern can solve this problem. Then you can get rid of the repetitive synchronization code. Like the following picture shows:

???
JMX Notification Model
?

Fortunately, we have existent?lib to provide synchronized list, we can replace the original ArrayList with following one:

?

    List<IListener> listenerList = Collections.synchronizedList(new ArrayList<IListener>());
  

???But I recommend you to use CopyOnWriteArrayList, no matter what operations(set,add and so on) on this list, it would make a fresh copy of underlying array of this list. And more important, when created its corrsponding iterator, it would hold a reference of?that underlying array of this list on that point.

??

    #CopyOnWriteArrayList
    public ListIterator<E> listIterator() {
        return new COWIterator<E>(getArray(), 0);
    }
  

?? So the?iterator of this list wont?be interfered during its lifetime, that is to say, it won't be interfered during the publisher's notifying process.

??

?? As we metioned above, when using CopyOnWriteArrayList, we not only can remove the repetitive synchronization code, but also can get rid of the copy code during notifying process.

?

    public class PublisherImpl implements IPublisher {
	...
	
	List<IListener> listenerList = new CopyOnWriteArrayList<IListener>();

	public void notifyEvent(IEvent event) {
		for (IListener li : listenerList)
			getExecutor().execute(new SendNotifJob(li,event));
	}

	public  void register(IListener li) {
		listenerList.add(li);
	}

	public  void unregister(IListener li) {
		listenerList.remove(li);
	}
	
	...
}

  

?

?? All right, now let's take a look at the how to use listener. We all know that, we might have many listeners registered in the publisher, and we might have different type of event. And generally speaking, a listener only respond to a specific event type.

???

    public void handleEvent(IEvent event) {
		 if(event.getType().equals("SomeType"))
		  {
	                        //do sth
		   }}
  

???? And sometimes it does not only depend on the event's type, it might depends on other event attributes too. So sometimes we have to add many if sentences in our listeners, can't we just separate the filterable action from the business logic we do in the listener? Of course, we can, use filter. In most of the situations, a listener can have its own filter, in order to meet that demand, we need to improve our IPublisher.

??? First, add a new IFilter interface

???

    public interface IFilter {
	public void isEventEnable(IEvent event);
}
  

?

?? Secondly, modify our IPublisher and PublisherImpl class.

??

    public interface IPublisher extends IExecutorHandler {

	public void register(IListener li,IFilter filter);
	
	public void unregister(IListener li,IFilter filter);
	
	...
}
  

?

??? Because we have added a new IFilter parameter to the register() method and unregister() method, we need to hold the reference to the IFilter object too. Therefore, we wrap IListener object and IFilter object in a new ListenerInfo object.

??

???

    private class ListenerInfo {
		IListener listener;
		IFilter filter;

		public ListenerInfo(IListener listener, IFilter filter) {
			this.listener = listener;
			this.filter = filter;
		}

		public boolean equals(Object obj) {
			{
				if (!(obj instanceof ListenerInfo))
					return false;
				ListenerInfo li = (ListenerInfo) obj;
				return (li.listener.equals(listener) && li.filter
						.equals(filter));
			}
		}
	}
  

?

?? Then our modified PublisherImpl:

??

    List<ListenerInfo> listenerList = new CopyOnWriteArrayList<ListenerInfo>();

	public void notifyEvent(IEvent event) {
		for (ListenerInfo li : listenerList) {
			if (li.filter != null && li.filter.isEventEnable(event))
				getExecutor().execute(new SendNotifJob(li.listener, event));
		}
	}

	public void register(IListener li, IFilter filter) {
		listenerList.add(new ListenerInfo(li, filter));
	}

	public void unregister(IListener li, IFilter filter) {
		listenerList.remove(new ListenerInfo(li, filter));
	}
  

?

?? The last is about how we use the filter:

??

    	// add new listener
		publisher.register(new IListener() {
			public void handleEvent(IEvent event) {
				System.out.println(event.getType());
			}
		}, new IFilter() {
			public boolean isEventEnable(IEvent event) {
				return event.getType().equals("someType");
			}
		});
  

?

?? After we introduced the observer pattern, it's time to involve JMX notification in. If we see the class diagram of JMX Notification Model, we'll find that it is as alike as the observer pattern we metioned above.

??
JMX Notification Model
A NotificationBroadcaster is actually a IPublisher, a NotificationListener is a IListener, a NotificationFilter is a IFilter and a Notification is a IEvent. As we said, NotificationBroadcaster? can add, remove listener, and send notification:


JMX Notification Model
?Pay attention to addNotificationListener() method, you will notice there has?a third parameter handback object, this object will be sent to NotificationListener without modification when a notification is emitted. As javadoc said, it is used to associate information regarding the MBean emitter.
JMX Notification Model
?And the NotificationFilter is almost the same as IFilter as below:


JMX Notification Model
?

Now let's take a look at the Notification: Notification has several constructors which hold the required info.

    public Notification(String type, Object source, long sequenceNumber, long timeStamp, String message) 

public Notification(String type, Object source, long sequenceNumber, long timeStamp)

public Notification(String type, Object source, long sequenceNumber, String message)

public Notification(String type, Object source, long sequenceNumber)
  

?

  • type->the notification type, such as 'jmx.monitor.error.threshold', of course,you can define your custom notification type.
  • source->the source object which send the notification
  • sequenceNumber->sometimes we need this number to indicate the order in relation of events from the source.
  • timeStamp->the notification emission date
  • message->the detailed message

?What we should pay attention to is the NotificationBroadcasterSupport class, if you look into the code of it, you would find that the PublisherImpl class described above?and it are so much alike, well, I admit that I intentionally?evolved the PublisherImpl class?to NotificationBroadcasterSupport since this is a article of JMX Notification Model. You can use the JMX Notification Model like the Observer pattern we described above.

?

????? Before we finish this article, I would like you?to know there still exist a problem in our observer example, as we know, every operations(add,set and so on) on the CopyOnWriteArrayList will cause a fresh copy, it is not good, is it? It is ok when there are not too many listeners registered in the publisher, but what if the size of the registered listeners is 1000 or 10000? If so, that would be a problem to make copy frequently. Now?I want to recommend you a good solution that can ease the performance which I learn from others. That is, use a linked list instead of CopyOnWriteArrayList, of course, it must be synchronized, when adding a new listener into it, just insert the incoming listener on the first place of the linked list, then we can avoid making fresh copy when registering. We only make copy when unregistering the listener.

?

Register a new listener to the linked list:


JMX Notification Model
?

Unregister?a listener during the notifying process


JMX Notification Model
?By this way,?in addition to?avoid making copy when registering new listener, but also avoid the unregister problem when unregistering listeners.
?

JMX Notification Model


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 国产一级特黄aaaa大片野外 | 久久综合久久鬼色 | 青青免费视频视频在线 | 亚洲国产二区 | 亚洲精品中文字幕乱码一区二区 | 欧美精品成人久久网站 | 亚洲精品乱码国产精品乱码 | 愉拍自拍 | 国产激情久久久久影 | 成人精品一区二区激情 | 99久久综合精品国产 | 国产精品你懂的在线播放 | 欧美成人xxxx | 妖精视频一区二区三区 | 欧美成人在线视频 | 天天操夜操| 国产高清不卡视频 | 欧美精品在线一区 | 深夜免费福利 | 国产剧情一区二区三区 | 嫩模在线 | 又爽又黄又无遮挡的视频在线观看 | 免费爱爱视频网站 | 狠狠色丁香婷婷综合久久来 | 98在线视频噜噜噜国产 | 午夜久久免费视频 | 免费在线亚洲 | 日本不卡专区 | 中日韩欧美在线观看 | 欧美ucjizz免费播放器 | 亚洲欧洲高清 | 99re热这里只有精品视频 | 免费国产a国产片高清不卡 免费国产阿v视频在线观看 | 最新国产中文字幕 | 色偷偷亚洲 | 亚洲系列中文字幕一区二区 | 亚洲精品一区二区深夜福利 | 四虎永久影院 | 国产高清精品91在线 | 国内夫妇精品对白在线播放 | 日本三级欧美三级 |