如何在Java中使用单独的线程调用方法?


126

假设我有一个方法doWork()。我如何从一个单独的线程(不是主线程)中调用它。


关于这个最近的相关问题,碰巧有一些例子:杀死Java中的无限循环
Greg Hewgill,2010年

stackoverflow.com/questions/36832094/…我有一个类似的问题,请帮我解决这个问题
Sruthi Acg 2016年

您可能还想看看Reactive Java blog.danlew.net/2014/09/15/grokking-rxjava-part-1用于异步任务
Nathan Dunn

Answers:


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的并发教程以开始。

如果您的方法将被频繁调用,那么每次创建一个新线程可能都不值得,因为这是一项昂贵的操作。最好使用某种类型的线程池。看一看FutureCallableExecutor类的java.util.concurrent包。


1
如果您要传递一个变量该怎么办?
路易·瑞斯

8
run()方法不带参数,因此您无法在其中传递变量。我建议您在构造函数中传递它-我将编辑答案以表明这一点。
Noel M

1
有没有一种在其他线程中调用1方法的简便方法?我知道new Thread() { public void run() {myMethod();}}.start();这是最短的吗?
史蒂文·罗斯

@NoelM您能解释一下您和MANN答案之间的区别吗?
Asif Mushtaq,2015年

2
MANN的答案使用的是我的匿名实现,Runnable它是扩展的类Runnable。而且因为这样做,我有了自己的构造函数,该构造函数将状态传递到实例化的对象中。
Noel M

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

这完全适合我的工作。需要使用观察者模式同时运行Web服务和更新进度条。
dpi

@Ashish:请解释一下,为什么要编辑?
曼2014年

1
@AshishAggarwal:有人未经作者许可而这样做,对我来说很奇怪!
曼2014年

@MANN可以解释为什么在Thread参数中使用run方法吗?有更好的表现吗?
阿西夫·穆什塔克

1
我们是否需要显式终止线程?是否没有通过不显式终止线程来造成内存泄漏的风险?还是完成后线程终止run()
uv

59

在Java 8中,您可以使用一行代码来完成此操作。

如果您的方法不带任何参数,则可以使用方法参考:

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

否则,您可以在lambda表达式中调用该方法:

new Thread(() -> doWork(someParam)).start();

抱歉,把它带回来,但这到底是什么->意思?
凯尔(Kyle)2015年

1
这是用于创建lambda表达式的语法。看一下这些链接以获取更多信息:Java中的'->'是什么?Java™教程-Lambda表达式
亚伦·科恩

@AaronCohn很棒的家伙!您知道Java线程的任何替代方法吗?我来自Python的世界,whre我们将使用Celery task queue为异步的东西
CESCO

Java具有处理线程的更高级别的抽象,但是也许您正在寻找更像Akka的东西?
亚伦·科恩

8

调用事物的另一个更快的选择(例如DialogBoxes和MessageBoxes以及为非线程安全的方法创建单独的线程)是使用Lamba Expression

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

3

前一段时间,我编写了一个简单的实用程序类,该类使用JDK5执行程序服务并在后台执行特定的进程。由于doWork()通常具有一个空返回值,因此您可能想使用此实用工具类在后台执行它。

请参阅这篇文章,我记录了该实用程序。


6
Future和Callable为您做这种事情。
阿米尔·阿富汗尼

是的,他们愿意。这里的想法是抽象异步包装器后面的接口。
raja kolluru

链接断开(404)。
palacsint

3

要使用RxJava 2.x实现此目的,可以使用:

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

subscribeOn()方法指定在哪个调度程序上运行操作-RxJava有几个预定义的调度程序,其中包括Schedulers.io()一个用于I / O操作的线程池,以及Schedulers.computation()一个用于CPU密集型操作的线程池。


3

如果您至少使用Java 8,则可以使用runAsyncCompletableFuture中的方法

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

如果您需要返回结果,请supplyAsync改用

CompletableFuture.supplyAsync(() -> 1);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.