Alternative 2: Thread Suspend and Resume"

From Documentation
m (Created page with '{{ZKDevelopersGuidePageHeader}} With the help of server push, you don't have to take care about the problem of multi threads. However, if you would like to handle this job by yo…')
 
m (correct highlight (via JWB))
 
Line 3: Line 3:
 
With the help of server push, you don't have to take care about the problem of multi threads. However, if you would like to handle this job by yourself, you have to conform with the following rules due to the limitations of HTTP.
 
With the help of server push, you don't have to take care about the problem of multi threads. However, if you would like to handle this job by yourself, you have to conform with the following rules due to the limitations of HTTP.
  
* Use the <tt>wait </tt>method in the <javadoc>org.zkoss.zk.ui.Executions</javadoc> class to suspend the event handler itself, after creating a working thread.
+
* Use the <code>wait </code>method in the <javadoc>org.zkoss.zk.ui.Executions</javadoc> class to suspend the event handler itself, after creating a working thread.
 
* Because the working thread is not an event listener, it ''cannot'' access any components, unless the components don't belong to any desktop. Thus, you might have to pass necessary information manually before starting the working thread.
 
* Because the working thread is not an event listener, it ''cannot'' access any components, unless the components don't belong to any desktop. Thus, you might have to pass necessary information manually before starting the working thread.
 
* Then, the working thread could crush the information and create components as necessary. Just don't reference any component that belongs to any desktop.
 
* Then, the working thread could crush the information and create components as necessary. Just don't reference any component that belongs to any desktop.
* Use the <tt>notify(Desktop desktop, Object flag)</tt> or <tt>notifyAll(Desktop desktop, Object flag)</tt> method in the <javadoc>org.zkoss.zk.ui.Executions</javadoc> class in the working thread to resume the event handler, after the working thread finishes.
+
* Use the <code>notify(Desktop desktop, Object flag)</code> or <code>notifyAll(Desktop desktop, Object flag)</code> method in the <javadoc>org.zkoss.zk.ui.Executions</javadoc> class in the working thread to resume the event handler, after the working thread finishes.
 
* The resumed event handler won't be executed immediately until another event is sent from the client. To enforce an event to be sent, you could use a timer component (<javadoc>org.zkoss.zul.Timer</javadoc>) to fire an event a moment later or periodically. This event listener for this timer could do nothing or update the progress status.
 
* The resumed event handler won't be executed immediately until another event is sent from the client. To enforce an event to be sent, you could use a timer component (<javadoc>org.zkoss.zul.Timer</javadoc>) to fire an event a moment later or periodically. This event listener for this timer could do nothing or update the progress status.
  
Line 51: Line 51:
 
</source>
 
</source>
 
   
 
   
Then, we have a ZUML page to invoke this working thread in an event listener, say <tt>onClick</tt>.
+
Then, we have a ZUML page to invoke this working thread in an event listener, say <code>onClick</code>.
  
 
<source lang="xml" >
 
<source lang="xml" >
Line 67: Line 67:
 
</source>
 
</source>
  
Notice that we have to use a timer to really resume the suspended the event listener (<tt>onClick</tt>). It looks odd, but it is a must due to the HTTP limitation: to keep Web page alive at the browser, we have to return the response when the event processing is suspended. Then, when the working thread completes its job and notifies the even listener, the HTTP request was already gone. Therefore, we need a way to 'piggyback' the result, which the timer is used for.
+
Notice that we have to use a timer to really resume the suspended the event listener (<code>onClick</code>). It looks odd, but it is a must due to the HTTP limitation: to keep Web page alive at the browser, we have to return the response when the event processing is suspended. Then, when the working thread completes its job and notifies the even listener, the HTTP request was already gone. Therefore, we need a way to 'piggyback' the result, which the timer is used for.
  
More precisely, when the working thread notifies the event listener to resume, ZK only adds it to a waiting list. And, the listener is really resumed when another HTTP request arrives (in the above example, it is the <tt>onTimer</tt> event)
+
More precisely, when the working thread notifies the event listener to resume, ZK only adds it to a waiting list. And, the listener is really resumed when another HTTP request arrives (in the above example, it is the <code>onTimer</code> event)
  
In this simple example, we do nothing for the <tt>onTimer</tt> event. For a sophisticated application, you can use it to send back the progressing status.
+
In this simple example, we do nothing for the <code>onTimer</code> event. For a sophisticated application, you can use it to send back the progressing status.
  
 
{{ ZKDevelopersGuidePageFooter}}
 
{{ ZKDevelopersGuidePageFooter}}

Latest revision as of 10:35, 19 January 2022

DocumentationZK Developer's GuideAdvanced ZKLong OperationsAlternative 2: Thread Suspend and Resume
Alternative 2: Thread Suspend and Resume


Stop.png This documentation is for an older version of ZK. For the latest one, please click here.


With the help of server push, you don't have to take care about the problem of multi threads. However, if you would like to handle this job by yourself, you have to conform with the following rules due to the limitations of HTTP.

  • Use the wait method in the Executions class to suspend the event handler itself, after creating a working thread.
  • Because the working thread is not an event listener, it cannot access any components, unless the components don't belong to any desktop. Thus, you might have to pass necessary information manually before starting the working thread.
  • Then, the working thread could crush the information and create components as necessary. Just don't reference any component that belongs to any desktop.
  • Use the notify(Desktop desktop, Object flag) or notifyAll(Desktop desktop, Object flag) method in the Executions class in the working thread to resume the event handler, after the working thread finishes.
  • The resumed event handler won't be executed immediately until another event is sent from the client. To enforce an event to be sent, you could use a timer component (Timer) to fire an event a moment later or periodically. This event listener for this timer could do nothing or update the progress status.

Example: A Working Thread Generates Labels Asynchronously

Assume we want create a label asynchronously. Of course, it is non-sense to do such a little job by applying multi-threading, but you can replace the task with sophisticated one.

 //WorkingThread
 package test;

import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zul.Label;


 public class WorkingThread extends Thread {
     private static int _cnt;
     private Desktop _desktop;
     private Label _label;
     private final Object _mutex = new Integer(0);
 
     /** Called by thread.zul to create a label asynchronously.
    *To create a label, it start a thread, and wait for its completion.
    */
     public static final Label asyncCreate(Desktop desktop)
         throws InterruptedException {
         final WorkingThread worker = new WorkingThread(desktop);
         synchronized (worker._mutex) { //to avoid racing
             worker.start();
             Executions.wait(worker._mutex);
             return worker._label;
         }
     }
     public WorkingThread(Desktop desktop) {
         _desktop = desktop;
     }
     public void run() {
             _label = new Label("Execute "+ ++_cnt);
             synchronized (_mutex) { //to avoid racing
             Executions.notify(_desktop, _mutex);
         }
     }
 }

Then, we have a ZUML page to invoke this working thread in an event listener, say onClick.

<window id="main" title="Working Thread">
    <button label="Start Working Thread">
        <attribute name="onClick">
         timer.start();
         Label label = test.WorkingThread.asyncCreate(desktop);
         main.appendChild(label);
         timer.stop()
        </attribute>
    </button>
    <timer id="timer" running="false" delay="1000" repeats="true"/>
</window>

Notice that we have to use a timer to really resume the suspended the event listener (onClick). It looks odd, but it is a must due to the HTTP limitation: to keep Web page alive at the browser, we have to return the response when the event processing is suspended. Then, when the working thread completes its job and notifies the even listener, the HTTP request was already gone. Therefore, we need a way to 'piggyback' the result, which the timer is used for.

More precisely, when the working thread notifies the event listener to resume, ZK only adds it to a waiting list. And, the listener is really resumed when another HTTP request arrives (in the above example, it is the onTimer event)

In this simple example, we do nothing for the onTimer event. For a sophisticated application, you can use it to send back the progressing status.



Last Update : 2022/01/19

Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.