How to deal with multiple threads in one class?

旧街凉风 提交于 2019-12-03 02:58:09

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.

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.

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.

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.

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();

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());
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!