What if I need to return an object from thread's runnable object?
What I need is to return token
object as a result of adapter.authenticate()
operation placed in thread. Have no idea how to re开发者_StackOverflowturn an object from there, please advice. Thank you.
public Token authenticate(final String email, final String password) {
Thread mThread = new Thread(new Runnable() {
@Override
public void run() {
try {
token = adapter.authenticate(email, password); // I need token to return with authenticate() method.
} catch (NotAuthenticatedException e) {
}
}
});
mThread.start();
}
Try this:
public Token authenticate(final String email, final String password) {
final Token[] tokens = new Token[1];
Thread mThread = new Thread(new Runnable() {
@Override
public void run() {
try {
tokens[0] = adapter.authenticate(email, password);
} catch (NotAuthenticatedException e) {
}
}
});
mThread.start();
mThread.join();
return tokens[0];
}
Explanation:
- You can't make
token
aToken
because it has to befinal
. - You need to
join
the thread, or else theauthenticate
is liable to return before the thread has set the token intokens[0]
.
It should also be noted that you are not achieving much by using a thread in that way. What you are doing is really just an expensive way of calling adapter.authenticate(email, password)
.
If your aim is to avoid blocking the UI while waiting for authentication, the solution needs to be more complicated. Basically, you need to change your application so that the view elements that require authentication to have happened start out as disabled (e.g. they are greyed out / ignore clicks / whatever). You do the authentication is a separate thread as above, and when it completes you get it to send an event to the UI thread. On receiving that event, the UI thread should then enable the disabled view elements.
Implement the Callable interface. Treat the call method just like run, and you can return your token.
Why would you want to start something in another thread and then wait for the outcome? Just call adapter.authenticate()
directly.
If you need to the results of an asynchronous operation in the gui, then you need to use a callback method. you need to essentially use 2 runnables. the first runnable does the work on a separate thread. when that work is complete, the result should be passed into a second runnable which is passed to SwingUtilities.invokeLater
. The second runnable will be run on the EDT thread at the next available opportunity and can safely update the ui with the results of the asynchronous operation.
If you don't want the UI to freeze, you need to do something like this:
(Source is for illustration purpose only, has compile error etc. (for brevity))
class Sample {
static final Executor exec = Executors.newCachedThreadPool();
final Adapter adapter = new Adapter();
public Token processRequest(final Email email, final Password password){
Future<Token> future = exec.submit(
new Callable<Token>(){
@Override
public Token call(){
return adapter.authenticate(email, password);
}
});
//do some stuff
if(future.isDone()){
//Ah, it's done.
return future.get();
}
//Not done yet. do some more useful stuff.
//Nothing to do anymore. Just block on the future and
// wait until it's finished.
return future.get();
}
}
Or of course you can store the future somewhere associated with the session and only return when requested by the user etc.
Your authenticate()
method cannot return Token
(unless it can be a placeholder object) since for it to return straight away, the result may not have been discovered yet.
Have the outer object implement a callback method, something like void authenticationComplete(Token authToken)
and have your Runnable
call that method with the result when it arrives.
class Authenticator {
...
public void authenticate(final String email, final String password) {
new Thread(new Runnable() {
public void run() {
Authenticator.this.authenticationComplete(
adapter.authenticate(email, password)
);
}
}).start();
}
public void authenticationComplete(Token authToken) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Update your UI
}
});
}
}
精彩评论