可通过参数运行吗?


177

我需要一个“接受参数的可运行对象”,尽管我知道这种可运行对象实际上并不存在。

这可能表明我的应用程序设计存在根本缺陷,并且/或者疲倦的大脑中存在智力障碍,因此我希望在这里找到一些建议,以在违反基本的OO原则的情况下实现以下目标:

  private Runnable mOneShotTask = new Runnable(String str) {
    public void run(String str) {
       someFunc(str);
    }
  };  

任何想法如何完成上述工作?


7
现在您可以使用了Consumer<T>
Alex78191 '19

1
我已经阅读了这个问题的各种答案。似乎没有人告诉您可以仅通过添加适当的接口将所需的Runnable(带有一个,两个,三个或三个以上的args)添加到项目中,这使我感到奇怪。我在这里为感兴趣的人创建了评论要点:gist.github.com/jsfan3/3a66e711fd0fd233c5e4c467184adb7a
Francesco Galgani

这与“如何将参数传递给Java线程”不是重复的。现代的答案是,就像@ Alex78191说的:使用Consumer<T>
Epaga

Answers:


228

自从我最初发布此文章至今已经快9年了,说实话,Java从那时起取得了一些进步。我将原始答案留在下面,但无需人们去做。9年前,在代码审查期间,我会质疑他们为什么这样做,也许批准了,也许没有。有了可用的现代lambda,如此高投票的答案就建议一种过时的方法是不负责任的(公平地说,这种方法从一开始就值得怀疑...)在现代Java中,该代码审查将被立即拒绝,这将是建议:

void foo(final String str) {
    Thread t = new Thread(() -> someFunc(str));
    t.start();
}

和以前一样,读者可以通过练习以有意义的方式处理线程等细节。但坦率地说,如果您担心使用lambda,则应该更担心多线程系统。

原始答案,仅因为:

您可以在方法中声明一个类

void Foo(String str) {
    class OneShotTask implements Runnable {
        String str;
        OneShotTask(String s) { str = s; }
        public void run() {
            someFunc(str);
        }
    }
    Thread t = new Thread(new OneShotTask(str));
    t.start();
}

谢谢你们!所有建议的解决方案都指向相同的方法,但我只能接受一种方法。我不能自己提出这个建议,我一定很累。+1。
uTubeFan 2011年

18
实际上,大多数人不知道您可以在方法内部声明类。有人会认为这是不好的风格。我想这是一个品味问题。:)
corsiKa'5

3
公共接口ResultRunnable <T> {public void run(T result); }
Roman M

46

您可以将其放在函数中。

String paramStr = "a parameter";
Runnable myRunnable = createRunnable(paramStr);

private Runnable createRunnable(final String paramStr){

    Runnable aRunnable = new Runnable(){
        public void run(){
            someFunc(paramStr);
        }
    };

    return aRunnable;

}

(使用此参数时,我的参数是整数ID,用于创建ID-> myRunnables的哈希图。这样,我可以使用哈希图在处理程序中发布/删除不同的myRunnable对象。)


3
感谢您分享代码-当人们这样做时,我不仅喜欢笨拙,而且非常喜欢。一个问题-关于内存泄漏,上述方法是否可以?您通过的所有推荐信都会妥善处理?
nikib3ro 2012年

2
@ kape123答案是“取决于”。只要Runnable该方法返回的对象存在于任何地方,该对象paramStr就可能不符合垃圾回收的条件。如果对象存在但可能永远无法再次运行,则JIT(甚至javac)可能会决定将其从范围中删除,但是我们不应该依赖于此类优化,因为它们将来可能会更改。
corsiKa 2013年

“感谢共享代码-当人们这样做时,我不仅喜欢笨拙,而且我很喜欢。” - 什么?
罗布·格兰特

30
theView.post(new Runnable() {
    String str;
    @Override                            
    public void run() {
        par.Log(str);                              
    }
    public Runnable init(String pstr) {
        this.str=pstr;
        return(this);
    }
}.init(str));

创建返回对象本身的init函数并使用它初始化参数。


1
不幸的是,您将无法将其分配给变量并调用init()
Andrew Glukhoff

11

我使用以下实现Runnable接口的类。使用此类,您可以轻松地创建带有参数的新线程

public abstract class RunnableArg implements Runnable {

    Object[] m_args;

    public RunnableArg() {
    }

    public void run(Object... args) {
        setArgs(args);
        run();
    }

    public void setArgs(Object... args) {
        m_args = args;
    }

    public int getArgCount() {
        return m_args == null ? 0 : m_args.length;
    }

    public Object[] getArgs() {
        return m_args;
    }
}

2
您将如何使用此抽象类运行带有参数的可运行对象?
EZDsIt

我更喜欢将构造函数与参数一起使用, public RunnableArg(Object... args) { setArgs(args); } 然后描述本地类: class ActionArg extends RunnableArg { public ActionArg(Object... arg) { super(arg); } @Override public void run() { /* getArgs() and process them */ } } 并使用它 Thread t = new Thread(new ActionArg( %param_object(s)% )); t.start();
GSD.Aaz



5

我首先想知道您要在这里完成什么,需要将参数传递给新的Runnable()或run()。通常的方法应该是拥有一个Runnable对象,该对象在启动之前通过设置成员变量将data(str)传递到其线程。然后,run()方法使用这些成员变量值来执行someFunc()

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.