如何将参数传递给Java线程?

时间:2009-05-18 10:37:02

标签: java multithreading

有人可以向我建议如何将参数传递给线程吗?

另外,它如何用于匿名类?

19 个答案:

答案 0 :(得分:343)

您需要将构造函数中的参数传递给Runnable对象:

public class MyRunnable implements Runnable {

   public MyRunnable(Object parameter) {
       // store parameter for later user
   }

   public void run() {
   }
}

然后调用它:

Runnable r = new MyRunnable(param_value);
new Thread(r).start();

答案 1 :(得分:102)

对于匿名类:

在回答问题编辑时,这里是如何为匿名类

工作的
   final X parameter = ...; // the final is important
   Thread t = new Thread(new Runnable() {
       p = parameter;
       public void run() { 
         ...
       };
   t.start();

命名类:

您有一个扩展Thread(或实现Runnable)的类以及一个包含您想要传递的参数的构造函数。然后,当你创建新线程时,你必须传入参数,然后启动线程,如下所示:

Thread t = new MyThread(args...);
t.start();

Runnable是比Thread BTW更好的解决方案。所以我更喜欢:

   public class MyRunnable implements Runnable {
      private X parameter;
      public MyRunnable(X parameter) {
         this.parameter = parameter;
      }

      public void run() {
      }
   }
   Thread t = new Thread(new MyRunnable(parameter));
   t.start();

这个答案与这个类似的问题基本相同:How to pass parameters to a Thread object

答案 2 :(得分:40)

通过Runnable或Thread类的构造函数

class MyThread extends Thread {

    private String to;

    public MyThread(String to) {
        this.to = to;
    }

    @Override
    public void run() {
        System.out.println("hello " + to);
    }
}

public static void main(String[] args) {
    new MyThread("world!").start();
}

答案 3 :(得分:18)

这个答案来得很晚,但也许有人会觉得它很有用。它是关于如何将参数传递给Runnable,甚至没有声明命名类(对于内联器很方便):

String someValue = "Just a demo, really...";
new Thread(new Runnable() {
    private String myParam;
    public Runnable init(String myParam) {
        this.myParam = myParam;
        return this;
    }
    @Override
    public void run() {
        System.out.println("This is called from another thread.");
        System.out.println(this.myParam);
    }
}.init(someValue)).start();

当然,您可以将start的执行推迟到更方便或适当的时刻。这取决于init方法的签名(所以它可能需要更多和/或不同的参数),当然还有它的名称,但基本上你会有一个想法。

事实上,还有另一种方法可以使用初始化程序块将参数传递给匿名类。考虑一下:

String someValue = "Another demo, no serious thing...";
int anotherValue = 42;

new Thread(new Runnable() {
    private String myParam;
    private int myOtherParam;
    {
        this.myParam = someValue;
        this.myOtherParam = anotherValue;
    }
    @Override
    public void run() {
        System.out.println("This comes from another thread.");
        System.out.println(this.myParam + ", " + this.myOtherParam);
    }
}).start();

所有这些都发生在初始化程序块内。

答案 4 :(得分:16)

创建线程时,需要Runnable的实例。传递参数的最简单方法是将其作为参数传递给构造函数:

public class MyRunnable implements Runnable {

    private volatile String myParam;

    public MyRunnable(String myParam){
        this.myParam = myParam;
        ...
    }

    public void run(){
        // do something with myParam here
        ...
    }

}

MyRunnable myRunnable = new myRunnable("Hello World");
new Thread(myRunnable).start();

如果您想在线程运行时更改参数,只需向运行类添加setter方法:

public void setMyParam(String value){
    this.myParam = value;
}

一旦你有了这个,你可以通过这样调用来改变参数的值:

myRunnable.setMyParam("Goodbye World");

当然,如果您想在参数更改时触发操作,则必须使用锁定,这会使事情变得更加复杂。

答案 5 :(得分:9)

要创建线程,通常可以创建自己的Runnable实现。将参数传递给此类构造函数中的线程。

class MyThread implements Runnable{
   private int a;
   private String b;
   private double c;

   public MyThread(int a, String b, double c){
      this.a = a;
      this.b = b;
      this.c = c;
   }

   public void run(){
      doSomething(a, b, c);
   }
}

答案 6 :(得分:8)

您可以扩展Thread classRunnable class并根据需要提供参数。 docs中有一些简单的例子。我会把它们移到这里:

 class PrimeThread extends Thread {
     long minPrime;
     PrimeThread(long minPrime) {
         this.minPrime = minPrime;
     }

     public void run() {
         // compute primes larger than minPrime
          . . .
     }
 }

 PrimeThread p = new PrimeThread(143);
 p.start();

 class PrimeRun implements Runnable {
     long minPrime;
     PrimeRun(long minPrime) {
         this.minPrime = minPrime;
     }

     public void run() {
         // compute primes larger than minPrime
          . . .
     }
 }


 PrimeRun p = new PrimeRun(143);
 new Thread(p).start();

答案 7 :(得分:7)

编写一个实现Runnable的类,并在适当定义的构造函数中传递您需要的任何内容,或编写一个使用适当定义的构造函数扩展Thread的类,该构造函数使用适当的参数调用super()。

答案 8 :(得分:5)

从Java 8开始,您可以使用lambda捕获effectively final的参数。例如:

final String param1 = "First param";
final int param2 = 2;
new Thread(() -> {
    // Do whatever you want here: param1 and param2 are in-scope!
    System.out.println(param1);
    System.out.println(param2);
}).start();

答案 9 :(得分:3)

您可以从Runnable派生一个类,并在构造期间(比方说)传递参数。

然后使用Thread.start(Runnable r);

启动它

如果你的意思是线程正在运行,那么只需在调用线程中保存对派生对象的引用,并调用适当的setter方法(在适当的地方进行同步)

答案 10 :(得分:3)

通过start()和run()方法传递参数:

// Tester
public static void main(String... args) throws Exception {
    ThreadType2 t = new ThreadType2(new RunnableType2(){
        public void run(Object object) {
            System.out.println("Parameter="+object);
        }});
    t.start("the parameter");
}

// New class 1 of 2
public class ThreadType2 {
    final private Thread thread;
    private Object objectIn = null;
    ThreadType2(final RunnableType2 runnableType2) {
        thread = new Thread(new Runnable() {
            public void run() {
                runnableType2.run(objectIn);
            }});
    }
    public void start(final Object object) {
        this.objectIn = object;
        thread.start();
    }
    // If you want to do things like setDaemon(true); 
    public Thread getThread() {
        return thread;
    }
}

// New class 2 of 2
public interface RunnableType2 {
    public void run(Object object);
}

答案 11 :(得分:2)

有一种将参数传递给runnables的简单方法。 代码:

public void Function(final type variable) {
    Runnable runnable = new Runnable() {
        public void run() {
            //Code adding here...
        }
    };
    new Thread(runnable).start();
}

答案 12 :(得分:2)

在Java 8中,您可以将lambda表达式与Concurrency API& ExecutorService作为直接使用线程的更高级替代品:

  

newCachedThreadPool()创建一个创建新线程的线程池   根据需要,但会重用以前构造的线程   可用。这些池通常会提高执行许多短期异步任务的程序的性能。

    private static final ExecutorService executor = Executors.newCachedThreadPool();

    executor.submit(() -> {
        myFunction(myParam1, myParam2);
    });

另请参阅executors javadocs

答案 13 :(得分:1)

另一个选择;这种方法允许您像使用异步函数调用一样使用Runnable项。如果您的任务不需要返回结果,例如它只是执行一些你不必担心如何传回"结果"。

此模式允许您重用项目,您需要某种内部状态。当不在构造函数中传递参数时,需要注意调解程序对参数的访问。如果您的用例涉及不同的呼叫者等,则可能需要更多检查。

public class MyRunnable implements Runnable 
{
  private final Boolean PARAMETER_LOCK  = false;
  private X parameter;

  public MyRunnable(X parameter) {
     this.parameter = parameter;
  }

  public void setParameter( final X newParameter ){

      boolean done = false;
      synchronize( PARAMETER_LOCK )
      {
          if( null == parameter )
          {
              parameter = newParameter;
              done = true;
          }
      }
      if( ! done )
      {
          throw new RuntimeException("MyRunnable - Parameter not cleared." );
      }
  }


  public void clearParameter(){

      synchronize( PARAMETER_LOCK )
      {
          parameter = null;
      }
  }


  public void run() {

      X localParameter;

      synchronize( PARAMETER_LOCK )
      {
          localParameter = parameter;
      }

      if( null != localParameter )
      {
         clearParameter();   //-- could clear now, or later, or not at all ...
         doSomeStuff( localParameter );
      }

  }

}

线程t =新线程(新MyRunnable(参数));    t.start();

如果需要处理结果,则还需要在子任务完成时协调MyRunnable的完成。你可以传回一个电话或者等待线程'等等。

答案 14 :(得分:1)

我知道我已经晚了几年,但是我遇到了这个问题,并采取了非正统的方法。我想不上新课就去做,所以这就是我想出的:

int x = 0;
new Thread((new Runnable() {
     int x;
     public void run() {
        // stuff with x and whatever else you want
     }
     public Runnable pass(int x) {
           this.x = x;
           return this;
     }
}).pass(x)).start();

答案 15 :(得分:1)

不,您无法将参数传递给run()方法。签名告诉您(它没有参数)。可能最简单的方法是使用一个专门构建的对象,它在构造函数中获取一个参数并将其存储在最终变量中:

public class WorkingTask implements Runnable
{
    private final Object toWorkWith;

    public WorkingTask(Object workOnMe)
    {
        toWorkWith = workOnMe;
    }

    public void run()
    {
        //do work
    }
}

//...
Thread t = new Thread(new WorkingTask(theData));
t.start();

一旦你这样做了 - 你必须小心你传递给' WorkingTask'的对象的数据完整性。数据现在将存在于两个不同的线程中,因此您必须确保它是线程安全的。

答案 16 :(得分:1)

特别适用于Android

对于回调目的,我通常使用输入参数实现我自己的通用Runnable

public interface Runnable<TResult> {
    void run(TResult result);
}

用法很简单:

myManager.doCallbackOperation(new Runnable<MyResult>() {
    @Override
    public void run(MyResult result) {
        // do something with the result
    }
});

经理:

public void doCallbackOperation(Runnable<MyResult> runnable) {
    new AsyncTask<Void, Void, MyResult>() {
        @Override
        protected MyResult doInBackground(Void... params) {
            // do background operation
            return new MyResult(); // return resulting object
        }

        @Override
        protected void onPostExecute(MyResult result) {
            // execute runnable passing the result when operation has finished
            runnable.run(result);
        }
    }.execute();
}

答案 17 :(得分:0)

在您的班级中创建一个extends Threadimplements Runnable的局部变量。

public class Extractor extends Thread {
    public String webpage = "";
    public Extractor(String w){
        webpage = w;
    }
    public void setWebpage(String l){
        webpage = l;
    }

    @Override
    public void run() {// l is link
        System.out.println(webpage);
    }
    public String toString(){
        return "Page: "+webpage;
    }}

这样,您可以在运行变量时传递变量。

Extractor e = new Extractor("www.google.com");
e.start();

输出:

"www.google.com"

答案 18 :(得分:0)

首先我想指出其他答案是正确的。 但是,在构造函数中使用参数对你们所有人来说可能不是最好的主意。

在许多情况下,您会希望使用“匿名内部类”,并覆盖 run() 方法,因为为每次使用定义特定类是痛苦的。 (new MyRunnable(){...})

并且在您创建该 Runnable 时,您可能无法使用该参数将其传递到构造函数中。例如,如果您将此对象传递给一个方法,该方法将在单独的线程中执行一些工作,然后调用您的可运行对象,并将该工作的结果应用于它。

在那种情况下,使用这样的方法: public MyRunnable withParameter(Object parameter),可能会成为更有用的选择。

我不认为这是问题的最佳解决方案,但它可以完成工作。