blob: 3e9d86079ecbb81e5fcda7c731ef41f85bbe7c6d [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="copyright" content="Copyright (c) 2007, 2019 EclipseSource. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page."/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Threads in RAP</title>
<link rel="stylesheet" href="../../../PRODUCT_PLUGIN/book.css" type="text/css"/>
</head>
<body>
<h1>Threads in RAP</h1>
<p>
Like in SWT, we have to distiguish two types of threads, the UI thread and other, non-UI threads,
also called “background threads”.
</p>
<h2>The UI Thread</h2>
<p>
In SWT, the <em>UI thread</em> is the thread in which the Display was created.
Widgets may only be created and accessed in this thread.
In RWT, this is no different, and in addition to that, the UI thread also provides the scope of
the UI session.
Thus, all methods in RWT that require the current UI Session or application context
must be called from this thread.
This includes most methods of
<em><a href="../reference/api/org/eclipse/rap/rwt/RWT.html">RWT</a></em>, such as
<em><a href="../reference/api/org/eclipse/rap/rwt/RWT.html#getUISession--">RWT.getUISession()</a></em> and
<em><a href="../reference/api/org/eclipse/rap/rwt/RWT.html#getApplicationContext--">RWT.getApplicationContext()</a></em>),
but also the
<em><a href="../reference/api/org/eclipse/rap/rwt/SingletonUtil.html">SingletonUtil</a></em>.
</p>
<p>
Since entrypoints an all event listeners are executed in the UI thread,
all application code has full access by default.
However, when an application forks new threads (<q>non-UI</q> or <q>background</q> threads),
these threads cannot directly access the UI session or the application context.
See <a href="threads.html#access">Session access from a background threads</a>.
</p>
<h3 id="client">UI Updates from background threads</h3>
<p>
Any
<a href="client.html">RAP Client</a> that connects with a RAP server also stores some data,
usually for the duration of the UI Session.
Most notably, the client has a complete copy of the UI state, which it
presents to the user to interact with. It can only exchange data during HTTP requests,
which are triggered by user interactions. This means that if the UI state is changed by a
background thread, the client would normally not be updated until the next time the user does
something with the UI. See <a href="server-push.html">Server Push</a> for more.
</p>
<h2 id="uisession">Session access from a background thread</h2>
<p>
RWT determines the <a href="scopes.html#uisession">UI session</a>
based on the current thread. When <i>background
threads</i> try to do so, the code will fail with an <em>java.lang.IllegalStateException</em>,
saying that this thread has no access. This may happen when using any method of
<em><a href="../reference/api/org/eclipse/rap/rwt/RWT.html">RWT</a></em>
or
<em><a href="../reference/api/org/eclipse/rap/rwt/SingletonUtil.html">SingletonUtil</a></em>.
Example:
</p>
<pre class="lang-java">
// INCORRECT
// will throw IllegalStateException: No context available ...
Runnable runnable = new Runnable() {
public void run() {
UISession session = RWT.getUISession();
// ... or ...
Client client = RWT.getClient();
// ... or ...
MySessionSingleton sessionSingleton = MySessionSingleton.getInstance();
// ...
}
};
new Thread( runnable ).start();
</pre>
<p>
The solution is to run the code in question in the context of the UI session.
To do so, it must be wrapped in a runnable and executed using the method
<em style="white-space:nowrap;"><a href="../reference/api/org/eclipse/rap/rwt/service/UISession.html#exec-java.lang.Runnable-">UISession#exec( Runnable runnable )</a></em>.
This will execute the runnable in the context of the UI session, granting the code in its
<em>run()</em> method access to all session-scoped data.
However, the code can not access any widgets, because it is not executed in the UI Thread
(see <a href="#asyncexec">below</a>).
</p>
<p>
In case there is no reference to the current UISession available,
it can also be obtained from
<em style="white-space:nowrap;"><a href="../reference/api/org/eclipse/rap/rwt/RWT.html#getUISession--">RWT.getUISession( Display display )</a></em>.
</p>
<pre class="lang-java">
// CORRECT
final Display display = Display.getCurrent();
final Runnable runnable = new Runnable() {
public void run() {
UISession uiSession = RWT.getUISession( display );
uiSession.exec( new Runnable() {
public void run() {
Client client = RWT.getClient();
// ... or ...
MySessionSingleton sessionSingleton = MySessionSingleton.getInstance();
// ...
}
} );
}
};
new Thread( runnable ).start();
</pre>
<h2 id="asyncexec">Session access vs. UI access</h2>
<p>
<a href="/help/topic/org.eclipse.platform.doc.isv/guide/swt_threading.htm">
Like in SWT</a>, widgets can only be accessed from a <a href="scopes.html#uithread">UI thread</a>.
While <em>UISession#exec</em> executes a runnable in the context of the UI session,
it does <em>not</em> execute this runnable within the UI thread
but in the same thread that the method is called.
Hence, <em>UISession#exec</em> is not suitable to execute code that accesses the UI.
To do so,
<em><a href="../reference/api/org/eclipse/swt/widgets/Display.html#asyncExec-java.lang.Runnable-">Display#asyncExec</a></em>
(or <em><a href="../reference/api/org/eclipse/swt/widgets/Display.html#syncExec-java.lang.Runnable-">Display#syncExec</a></em>)
has to be used instead.
Please note that UI updates from a background thread will only be “pushed” to the client when the
<a href="server-push.html">Server Push</a> is active.
In contrast to <em>asyncExec</em>, running code using <em>UISession#exec</em> does not cause
any additional network traffic.
</p>
<p>
In summary, when a thread <i>only</i> needs to access the UI session context
(e.g. by using <em>SingletonUtil</em>
or <em>RWT.getClient</em>), <em>UISession#exec</em> should be used.
But when the UI needs to be updated, <em>Display#asyncExec</em> <i>must</i> be used, as it
runs the code in the UI thread and thereby gives access to session scope <i>and</i> widgets.
Using <em>UISession#exec</em>
from within the UI thread is pointless.
</p>
<h2>Using a Helper</h2>
<p>
It can be helpful to create a helper class like this:
</p>
<pre class="lang-java">
abstract class SessionRunnable implements Runnable {
final private UISession session;
public SessionRunnable() {
session = RWT.getUISession();
}
@Override
public void run() {
session.exec( new Runnable() {
@Override
public void run() {
SessionRunnable.this.runInSession();
}
} );
}
abstract void runInSession();
}
</pre>
<p>
The above example could then be shortened to this:
</p>
<pre class="lang-java">
final Runnable runnable = new SessionRunnable() {
@Override
public void runInSession() {
Client client = RWT.getClient();
// ... etc ...
}
};
new Thread( runnable ).start();
</pre>
</body>
</html>