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

有人能告诉我如何将参数传递给线程吗?

另外,匿名类是如何工作的?

431342 次浏览

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

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

您可以从Runnable派生一个类,并在构造过程中(例如)传入参数。

然后使用Thread启动它。开始(Runnable r);

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

你需要在构造函数中将参数传递给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();

对于匿名类:

在这里回答问题编辑是如何工作的匿名类

   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更好的解决方案。所以我更喜欢:

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

这个答案基本上与这个类似的问题相同:如何传递参数到线程对象

要创建线程,通常需要创建自己的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);
}
}

当你创建一个线程时,你需要一个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();

如果你想在线程运行时改变参数,你可以简单地给你的runnable类添加一个setter方法:

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

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

myRunnable.setMyParam("Goodbye World");

当然,如果您希望在参数更改时触发一个操作,则必须使用锁,这使事情变得相当复杂。

你可以扩展Thread classRunnable class,并提供你想要的参数。文档中有一些简单的例子。我将把它们移植到这里:

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

参数通过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);
}

还有一个选择;这种方法允许您像使用异步函数调用一样使用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(参数)); < / p > t.start ();

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

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();
}
有一种将参数传递到可运行对象的简单方法。 代码:< / p >
public void Function(final type variable) {
Runnable runnable = new Runnable() {
public void run() {
//Code adding here...
}
};
new Thread(runnable).start();
}

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

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”的对象的数据完整性。数据现在将存在于两个不同的线程中,因此您必须确保它是线程安全的。

这个答案来得很晚,但也许有人会觉得它有用。它是关于如何在不声明命名类的情况下将一个(多个)形参传递给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;
// instance initializer
{
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();

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

从Java 8开始,你可以使用lambda来捕获有效的最终的参数。例如:

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

在Java 8中,你可以使用lambda表达式和并发API &ExecutorService作为直接使用线程的更高级别替代品:

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

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


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

参见executors javadocs

在类中创建一个局部变量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"

我知道我迟到了几年,但我遇到了这个问题,并采取了一种非传统的方法。我想在不创建新类的情况下做到这一点,所以我想到了:

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();
首先,我想指出其他答案都是正确的。 然而,在构造函数中使用形参可能对所有人来说都不是最好的主意 在许多情况下,你会想要使用“匿名内部类”,并重写run()方法,因为为每个用途定义特定的类是痛苦的。 (new MyRunnable(){...}) < / p >

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

在这种情况下,使用如下方法: public MyRunnable withParameter(Object parameter),可能是更有用的选择

我并不是说这是解决问题的最好办法,但它可以解决问题。