Java: Потоки, работающие без всех классов, имеющих открытый void run ()? - PullRequest
2 голосов
/ 14 декабря 2011

У меня относительно большой объем кода, написанного без учета потоков.Я новичок в Java и вообще в программировании, поэтому у меня возникли небольшие проблемы с выяснением того, как запустить программу, которую я встроил в потоки, не возвращаясь ко всем моим классам и не изменив их на метод run ().Я даже не представляю, как это возможно, когда у меня есть несколько методов, которые должны вызываться отдельно от других классов.

Кажется, я не могу найти способ создать поток для (каждого / а)новый вызов кода из графического интерфейса.Скажем, у меня есть метод для вставки данных в базу данных.Метод назван и написан.Я мог бы поместить вызов этого класса и метода в мой main, но что тогда, когда я хочу вызвать какой-то другой метод?У меня есть как минимум 25+ методов, и я не вижу, чтобы мой основной класс был перегружен 25 раз как «Лучшая практика».Есть ли способ создать поток и дать ему объект для динамической обработки, так сказать?

Короче говоря: я хочу использовать потоки в моей программе, не перегружая основную, как мне это сделать?

Ответы [ 5 ]

3 голосов
/ 14 декабря 2011

Честно говоря, не существует универсального способа преобразования однопоточного приложения в многопоточное, потому что оно требует другого дизайна в зависимости от вашей цели.И «многопоточное приложение» на самом деле не является целью:)

Вы не указали, как создавали свой пользовательский интерфейс.Но если вы используете Swing и хотите выполнить какое-то длинное задание, не останавливая работу вашего пользовательского интерфейса, используйте SwingWorker

На заметке общего характера я бы рекомендовал прочитать книгу " Java Concurrency inПрактика ».Это очень хорошо.

1 голос
/ 14 декабря 2011

Нет необходимости, чтобы все ваши классы имели метод run или реализовали Runnable, обычно есть определенные вещи, которые вы хотите сделать в отдельном потоке, часто, чтобы вы не блокировали пользовательский интерфейс во время выполнения потенциально медленной операции, такой какобщаться с базой данных, файловой системой или сетью.

Самый простой способ - просто создать новый поток, когда вам нужно сделать это:

Thread t = new Thread() {
    public void run() {
         // do whatever work you want...
    }
};

t.start();
1 голос
/ 14 декабря 2011

Вам не нужно, чтобы каждый метод / класс выполнялся в своем собственном потоке или для реализации метода run. Что вы должны сделать, это то, что для каждого действия, которое может выполнить пользователь, должен быть соответствующий класс, который реализует Действие (или что-то подобное интерфейс). Когда пользователь вызывает действие в пользовательском интерфейсе, вы должны добавить это действие в очередь.

Затем отдельный пул потоков должен принимать действия из очереди и выполнять их (с помощью метода, предоставляемого интерфейсом действий).

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

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

0 голосов
/ 14 декабря 2011

Поскольку у вас нет потоков в вашем приложении в настоящее время, я бы посоветовал вам изучить использование среды Executor для распараллеливания вашего приложения.В обоих случаях вам придется создавать экземпляры Runnable.Книга JCIP содержит пример главы, которая поможет вам в этом.Если вы не хотите в конечном итоге создавать более 25 внутренних классов Runnable, вы можете просто создать один пользовательский класс Runnable, который использует отражение для вызова этих методов для вас :

public ReflectiveRunnable {

  private final Object target; // needs to be non-null
  private final String methodName;
  private final Object[] argValues;
  private final Class[] argClasses;

  public ReflectiveRunnable(Object target, String methodName, Object[] args) {
    this.target = target;
    this.methodName = methodName;
    this.argValues = args;
    this.argClasses = new Class[args.length];
    for (int i = 0; i < args.length; i++) {
      argClasses[i] = args[i].getClass();
    }
  }


  public void run() {
    try {
      final Class cl = target.getClass();
      final Method mthd=cl.getMethod(methodName, argClasses);
      mthd.invoke(target, argValues);
    } catch (final Exception e) {
      // handle exception
      e.printStackTrace();
    } 
  }
}
0 голосов
/ 14 декабря 2011

Вы можете создать анонимный внутренний класс, который делает все, что вам нужно.Рассмотрим что-то вроде следующего.Создается новый (безымянный) подкласс Runnable, который выполняет необходимые шаги.

public class GuiCommandDelegator {

    void performBackgroundSave(final Document document, final String filename) {
        Runnable runnable = new Runnable() {
            @Override void run() {
                document.save (filename);
            }
        };

        Thread thread = new Thread(runnable);
        thread.run();
    }

}

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

...