Как вызвать метод с отдельным потоком в Java?

126

допустим, у меня есть метод doWork(). Как мне вызвать его из отдельного потока (не из основного потока).

Луи Рис
источник
По этому недавнему связанному вопросу есть несколько примеров: уничтожение бесконечного цикла в java
Грег Хьюгилл,
stackoverflow.com/questions/36832094/… У меня аналогичная проблема, пожалуйста, помогите мне решить эту проблему
Sruthi Acg
Вы также можете взглянуть на Reactive Java blog.danlew.net/2014/09/15/grokking-rxjava-part-1 для асинхронных задач
Натан Данн

Ответы:

138

Создайте класс, реализующий Runnableинтерфейс. Поместите код, который вы хотите запустить, в run()метод - это метод, который вы должны написать, чтобы соответствовать Runnableинтерфейсу. В своем «основном» потоке создайте новый Threadкласс, передав конструктору экземпляр вашего Runnable, а затем вызовите start()его. startсообщает JVM, что нужно творить чудеса для создания нового потока, а затем вызывать ваш runметод в этом новом потоке.

public class MyRunnable implements Runnable {

    private int var;

    public MyRunnable(int var) {
        this.var = var;
    }

    public void run() {
        // code in the other thread, can reference "var" variable
    }
}

public class MainThreadClass {
    public static void main(String args[]) {
        MyRunnable myRunnable = new MyRunnable(10);
        Thread t = new Thread(myRunnable)
        t.start();
    }    
}

Чтобы начать работу , ознакомьтесь с руководством по параллелизму в Java .

Если ваш метод будет вызываться часто, возможно, не стоит каждый раз создавать новый поток, поскольку это дорогостоящая операция. Вероятно, было бы лучше использовать какой-либо пул потоков. Посмотрите Future, Callable, Executorклассов в java.util.concurrentпакете.

Ноэль М
источник
1
что, если есть переменная, которую вы хотите передать?
Луи Рис,
8
run()Метод не принимает никаких параметров, так что вы не можете передать переменную там. Я предлагаю вам передать его в конструкторе - я отредактирую свой ответ, чтобы показать это.
Noel M
1
Есть ли короткий способ вызвать 1 метод в другом потоке? Я знаю new Thread() { public void run() {myMethod();}}.start();дорогу, она самая короткая?
Стивен Руз
@NoelM, можете ли вы объяснить разницу между вашим ответом и ответом MANN?
Асиф Муштак
2
В ответе MANN используется анонимная реализация Runnable- мой класс расширяется Runnable. И поскольку я это сделал, у меня есть собственный конструктор, который передает состояние созданному объекту.
Ноэль М.
183
Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
        // code goes here.
    }
});  
t1.start();

или

new Thread(new Runnable() {
     @Override
     public void run() {
          // code goes here.
     }
}).start();

или

new Thread(() -> {
    // code goes here.
}).start();

или

Executors.newSingleThreadExecutor().execute(new Runnable() {
    @Override
    public void run() {
        myCustomMethod();
    }
});

или

Executors.newCachedThreadPool().execute(new Runnable() {
    @Override
    public void run() {
        myCustomMethod();
    }
});
MANN
источник
Это отлично сработало для того, что я делал. Требуется для одновременного запуска веб-службы и обновления индикатора выполнения с использованием шаблона наблюдателя.
dpi
@Ashish: Объясните, пожалуйста, что и почему редактировалось?
MANN
1
@AshishAggarwal: Мне кажется странным, когда кто-то делает это без разрешения автора!
MANN
@MANN, можете ли вы объяснить, почему вы используете метод run в параметре Thread? какая-нибудь лучшая производительность?
Асиф Муштак
1
Нужно ли нам явно прерывать поток? Нет ли риска возникновения утечки памяти из-за того, что поток явно не завершится? Или поток завершается, когда это делается run()?
theyuv
59

В Java 8 это можно сделать с помощью одной строчки кода.

Если ваш метод не принимает никаких параметров, вы можете использовать ссылку на метод:

new Thread(MyClass::doWork).start();

В противном случае вы можете вызвать метод в лямбда-выражении:

new Thread(() -> doWork(someParam)).start();
Аарон Кон
источник
извините, что вернул это, но что именно ->означает?
Кайл
1
Это синтаксис, используемый для создания лямбда-выражения. Взгляните на эти ссылки для получения дополнительной информации: Что делает '->' в Java? и Учебники по Java ™ - Лямбда-выражения
Аарон Кон,
@AaronCohn отличный человек! Вы знаете какие-нибудь альтернативы потокам в Java? Я пришел из мира Python, где мы бы использовали его Celery task queueдля асинхронных вещей
CESCO
В Java есть абстракции более высокого уровня для работы с потоками , но, может быть, вы ищете что-то более похожее на Akka ?
Аарон Кон
8

Еще одним более быстрым вариантом вызова вещей (например, DialogBoxes и MessageBoxes и создания отдельных потоков для небезопасных методов) было бы использование выражения Lamba Expression

  new Thread(() -> {
                      "code here"
            }).start();
Рохан Савант
источник
3

Некоторое время назад я написал простой служебный класс, который использует службу исполнителя JDK5 и выполняет определенные процессы в фоновом режиме. Поскольку doWork () обычно имеет возвращаемое значение void, вы можете использовать этот служебный класс для его выполнения в фоновом режиме.

См. Статью, в которой я описал эту утилиту.

раджа коллуру
источник
6
Future и Callable делают это за вас.
Амир Афгани
Да, они это делают. идея здесь состоит в том, чтобы абстрагироваться от интерфейса за асинхронной оболочкой.
раджа коллуру
Ссылка не работает (404).
palacsint
3

Для этого с RxJava 2.x вы можете использовать:

Completable.fromAction(this::dowork).subscribeOn(Schedulers.io().subscribe();

В subscribeOn()методе определяет , какой планировщик для запуска действия на - RxJava имеет несколько предопределенных планировщиков, в том числе , Schedulers.io()который имеет пул потоки , предназначенные для операций ввода / вывода, и Schedulers.computation()которая предназначена для процессоров интенсивных операций.

Клайд
источник
3

Если вы используете как минимум Java 8, вы можете использовать метод runAsyncиз класса CompletableFuture

CompletableFuture.runAsync(() -> {...});

Если вам нужно вернуть результат, используйте supplyAsyncвместо этого

CompletableFuture.supplyAsync(() -> 1);
k13i
источник