【问题标题】:How to call a method with a separate thread in Java?如何在 Java 中使用单独的线程调用方法?
【发布时间】:2010-08-15 22:30:59
【问题描述】:

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

【问题讨论】:

标签: java multithreading


【解决方案1】:
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 服务和更新进度条。
  • @Ashish:请解释一下编辑了什么内容和原因?
  • @AshishAggarwal:如果有人在未经作者许可的情况下这样做,我觉得很奇怪!
  • 我们需要显式终止线程吗?通过不显式终止线程是否存在创建内存泄漏的风险?或者线程在使用run() 完成后是否终止?
  • 在 Java 8 及更高版本中,我们可以用 () -> myCustomMethod() 替换 new Runnable() {...} 冗长的东西
【解决方案2】:

创建一个实现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's concurrency tutorial 以开始使用。

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

【讨论】:

  • 如果有你想传递的变量怎么办?
  • run() 方法没有参数,所以你不能在那里传递变量。我建议您在构造函数中传递它 - 我将编辑我的答案以显示这一点。
  • 在不同的线程中调用 1 个方法是否有捷径?我知道new Thread() { public void run() {myMethod();}}.start(); 方式,是最短的吗?
  • @NoelM 你能解释一下你的答案和 MANN 的答案之间的区别吗?
  • MANN 的答案使用了Runnable 的匿名实现——我的是一个扩展Runnable 的类。因为我已经这样做了,所以我有自己的构造函数,它将状态传递给实例化的对象。
【解决方案3】:

在 Java 8 中,您只需一行代码即可完成此操作。

如果你的方法不带任何参数,你可以使用方法引用:

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

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

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

【讨论】:

  • 很抱歉把这个带回来,但 -> 到底是什么意思?
  • 这是用于创建 lambda 表达式的语法。查看这些链接以获取更多信息:What does '->' do in Java?The Java™ Tutorials - Lambda Expressions
  • @AaronCohn 好东西!你知道Java中线程的任何替代品吗?我来自 Python 世界,我们会使用 Celery task queue 来处理异步内容
  • Java 有 higher level abstractions for dealing with Threads,但也许您正在寻找类似 @​​987654324@ 的东西?
  • 我的方法抛出异常。在您的第一个示例中,如何从线程中抛出异常?
【解决方案4】:

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

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

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

CompletableFuture.supplyAsync(() -> 1);

【讨论】:

    【解决方案5】:

    另一个更快的调用方法(如对话框和消息框以及为非线程安全方法创建单独的线程)是使用 Lamba 表达式

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

    【讨论】:

      【解决方案6】:

      要使用 RxJava 2.x 实现这一点,您可以使用:

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

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

      【讨论】:

        【解决方案7】:

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

        请参阅this article,我在其中记录了此实用程序。

        【讨论】:

        • Future 和 Callable 为你做这种事情。
        • 是的。这里的想法是抽象异步包装器背后的接口。
        • 链接已损坏 (404)。
        • @palacsint 我更改了链接。现在它将起作用。对此感到抱歉
        猜你喜欢
        • 2011-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-19
        • 2015-01-21
        • 1970-01-01
        • 2016-04-01
        • 2023-02-01
        相关资源
        最近更新 更多