Как вызвать метод с отдельным потоком в 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();
    }
});

Это отлично сработало для того, что я делал. Требуется для одновременного запуска веб-службы и обновления индикатора выполнения с использованием шаблона наблюдателя.
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);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.