Как бороться с несколькими потоками в одном классе? - PullRequest
9 голосов
/ 17 января 2010

Потоки часто проектируются двумя способами ( см. Руководства по Java ): либо путем расширения класса Thread, либо путем реализации класса Runnable. В любом случае вам нужно указать, что будет выполняться внутри потока.

Я разработал класс, адаптер для онлайн-ресурса, который получает различную информацию. Этот класс состоит из методов, таких как getInformationOfTypeA () и getInformationOfTypeB (). Оба содержат код для подключения к онлайн-ресурсам, поэтому оба должны быть пронизаны, чтобы избежать тупиков.

Вопрос в том, как мне это спроектировать? Я могу сделать это, как показано ниже, но тогда я могу реализовать только один метод:

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
  }

}

Другим способом было бы создание отдельных классов для каждого метода, но мне это кажется неестественным.

Кстати: я разрабатываю свое приложение в j2me

UPDATE:

Благодаря вашим ответам я считаю наиболее подходящим использование в качестве методов чего-то вроде следующего:

Что вы думаете об этом:

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

Что вы думаете об этом?

Ответы [ 6 ]

6 голосов
/ 17 января 2010

Мне кажется, у вас должно быть два разных класса: InformationOfTypeAFetcher и InformationOfTypeBFetcher, каждый из которых должен реализовать Runnable. Каждый из них может иметь ссылку на экземпляр вашего OnlineResourceAdapter (или что-то подобное), но если они делают разные вещи, они должны быть разных классов.

4 голосов
/ 17 января 2010

Работают два анонимных внутренних класса, как смутно предлагал Турбьёрн Равн Андерсен. Вот пример кода:

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: Да, предложенный вами способ - это хороший способ. Вы даже можете сделать методы статичными. Вы можете использовать "OnlineResourceAdapter.this." получить доступ к другим переменным для сохранения результатов в.

1 голос
/ 17 января 2010

Многие люди уже предложили хорошие методы, как это сделать, используя несколько классов. Поскольку вы, похоже, предпочитаете способ, который не требует нескольких классов, вы также можете рассмотреть возможность использования конструктора для предоставления информации о том, какой ресурс получить:

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
    }
}

Использование:

(new Thread(new OnlineResourceAdapter("A"))).start();
1 голос
/ 17 января 2010

Я не понимаю, почему вам не нравится идея создания нескольких классов, учитывая, что Java не поддерживает функции более высокого порядка, а изменяемая часть вашего кода - это алгоритм.

Но если вы хотите одну реализацию OnlineResourceAdapter, вы можете использовать шаблон Стратегии и сделать что-то вроде этого:

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

и тогда, конечно, вы создадите столько реализаций InformationGetter, сколько вам нужно.

Если подумать, оглядываясь назад на этот подход, OnlineResourceAdapter теперь ничего не добавляет, кроме как сделать InformationGetter работоспособным. Поэтому, если у вас нет веских причин не делать этого, я бы сказал, что InformationGetter реализует Runnable напрямую.

1 голос
/ 17 января 2010

Для каждого класса создайте анонимный класс на основе Runnable. Это позволит вам делать то, что вам нужно делать внутри метода run ().

0 голосов
/ 17 января 2010

Используйте анонимные классы типа Callable (которые, в отличие от Runnable, могут возвращать значения) и выполняйте их, используя Executor.Если логика для получения информации A и информации B очень похожа, вы, конечно, можете изменить ее и использовать один параметризованный внутренний класс Callables.

Я не уверен, что Callable и Executor являются частью спецификации J2ME, хотя,В стандартной Java я бы все равно пошел на Proxy подход и инкапсулировал бы внешний ресурс как интерфейс.

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