问题
Threads are often designed in two ways (see java tutorials): either by extending the Thread class or by implementing the Runnable class. Either way, you need to specify what will run inside the thread.
I designed a class, an adapter towards an online resource, that retrieves different kinds of information. This class consists of methods like getInformationOfTypeA() and getInformationOfTypeB(). Both contain code to connect to online resources, so both need to be threaded to avoid deadlocks.
The question is: how should I design this? I can do it like below, but then I can only implement one method:
public class OnlineResourceAdapter implements Runnable {
public void run() {
//get stuff from resource
getInformationOfTypeA();
}
public static void main(String args[]) {
(new Thread(new OnlineResourceAdapter ())).start();
}
public void getInformationOfTypeA(){
//get information of type A
}
public void getInformationOfTypeB(){
//get information of type B
}
}
Another way would be by creating separate classes for each method, but that seems unnatural to me.
Btw: I'm developing my application in j2me
UPDATE:
Thanks to your responses I think it is most suiting to use something like the following as methods:
What do you think of this:
public class OnlineResourceAdapter{
public void getInformationOfTypeA(){
Thread t = new Thread(new Runnable() {
public void run() {
//do stuff here
}
});
t.start();
}
public void getInformationOfTypeB(){
Thread t = new Thread(new Runnable() {
public void run() {
//do stuff here
}
});
t.start();
}
}
What do you think of this?
回答1:
It sounds to me like you should actually have two different classes: InformationOfTypeAFetcher
and InformationOfTypeBFetcher
, each of which should implement Runnable
. Each of them may have a reference to an instance of your OnlineResourceAdapter
(or something similar) but if they're doing different things, they should be different classes.
回答2:
Two anonymous inner classes, like Thorbjørn Ravn Andersen suggested vaguely above, works. Here is a code example:
public class OnlineResourceAdapter {
public final Runnable typeA;
public final Runnable typeB;
public OnlineResourceAdapter() {
typeA = new Runnable() {
public void run() {
OnlineResourceAdapter.this.getInformationOfTypeA();
}
};
typeB = new Runnable() {
public void run() {
OnlineResourceAdapter.this.getInformationOfTypeB();
// one can use a non-final typed variable
// to store, which then<1>
}
};
}
public static void main(String args[]) {
OnlineResourceAdapter x = new OnlineResourceAdapter();
new Thread(x.typeA).start(); // start A
new Thread(x.typeB).start(); // start B
// <1>can be accessed here.
}
public void getInformationOfTypeA(){
// get information of type A
// return the data or directly store in OnlineResourceAdapter.
}
public void getInformationOfTypeB(){
//get information of type B
}
}
Edit: Yes, you're proposed way is a good way. You can even make the methods static. You can use "OnlineResourceAdapter.this." to access other variables to store results in.
回答3:
For each class create an anonymous class based on Runnable. This will allow you to do what you need to do inside the run() method.
回答4:
I don't see why you don't like the idea of creating multiple classes, considering Java doesn't support higher-order functions and the changeable part of your code is the algorithm.
But if you wanted a single implementation of OnlineResourceAdapter
you could use the Strategy pattern and do something like this:
public interface InformationGetter {
public void getInformation();
}
public class OnlineResourceAdapter implements Runnable {
private final InformationGetter informationGetter;
public OnlineResourceAdapter(InformationGetter i) {
this.informationGetter = i;
}
public void run() {
//get stuff from resource
i.getInformation();
}
}
and then of course you would create as many implementations of InformationGetter
as you needed.
Come to think about it, looking back over this approach, OnlineResourceAdapter
now doesn't really add anything except making InformationGetter
runnable. So unless you have some compelling reason not to, I would say just have InformationGetter
implement Runnable
directly.
回答5:
Many people have already suggested good methods of how to do this using several classes. Since you seem to prefer a way which doesn't require multiple classes, you might also want to consider using the constructor to give information about which resource to fetch:
public class OnlineResourceAdapter implements Runnable
{
private string resourceType;
public OnlineResourceAdapter(string resourceType)
{
this.resourceType = resourceType;
}
public void run() {
if (resourceType.equals("A") {
getInformationOfTypeA();
} else {
// etc..
}
}
public void getInformationOfTypeA(){
//get information of type A
}
public void getInformationOfTypeB(){
//get information of type B
}
}
Usage:
(new Thread(new OnlineResourceAdapter("A"))).start();
回答6:
Use anonymous classes of type Callable
(which, in contrast to Runnable
, can return values) and execute them using an Executor
. If the logic to retrieve informationA and informationB is very similar, you may of course refactor that and use a single, parameterizes inner class of Callables.
I'm not sure if Callable and Executor are part of J2ME spec though. In standard Java, i'd go for a Proxy
approach anyway and encapsulate the external resource as interface.
public class AsyncMethodsTest {
public class OnlineResourceAdapter {
private final ExecutorService executor = Executors.newFixedThreadPool(2);
public String getInformationOfTypeA() throws InterruptedException, ExecutionException,
TimeoutException {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
// Connect to external resource
Thread.sleep(500);
return "A";
}
};
Future<String> submit = executor.submit(callable);
return submit.get(1000, TimeUnit.MILLISECONDS);
}
public String getInformationOfTypeB() throws InterruptedException, ExecutionException,
TimeoutException {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
// Connect to external resource
Thread.sleep(1500);
return "B";
}
};
Future<String> submit = executor.submit(callable);
return submit.get(1000, TimeUnit.MILLISECONDS);
}
}
@Test
public void testMethodCalls() throws Exception {
OnlineResourceAdapter adapter = new OnlineResourceAdapter();
assertNotNull(adapter.getInformationOfTypeA());
assertNotNull(adapter.getInformationOfTypeB());
}
}
来源:https://stackoverflow.com/questions/2081747/how-to-deal-with-multiple-threads-in-one-class