Java runnable with argument

Java Runnable Example

In this example, we will take a look into the Runnable interface in Java, and how it can be used in association with the Thread class to create and execute new threads in your program. We will also try to explain what a Runnable is and what’s the difference from Thread , as well as take a look into the different ways that you can implement Runnable in your code.

1. Runnables and Threads

Let’s start by talking about a very common confusion in Java. Runnables are NOT Threads. The Runnable interface is used to define a certain task that we want to execute, and the whole implementation of this task is inside its only method, run() (which accepts no arguments). The Runnable class by itself does not create a separate thread, because this is what Thread actually does. Thread is used to create a new execution path (a new thread), separate from the main program. By providing a Runnable as an argument to a Thread constructor, you are essentially giving access of the Runnable’s task (defined in the run() method), to a new Thread object. At any time during your program, you can start the new thread, by using Thread.start() and the Runnable’s code will start running.

Читайте также:  Html размеры полей форм

2. Why use Runnable?

  • Modularity: When you run a thread and it finishes running, there is no way to restart it. This could lead to a lot of code duplication in case of multithreading, where you need a certain task to run a number of times. Fortunately, you can create a Runnable instance which can be reused in any number of threads.
  • Ease of use: Runnable only has one method, public void run() . It accepts no arguments and is as simple as possible. Thread has many methods that need to be taken into account making it very cumbersome to work with, and the extra overhead is always an issue.
  • Inheritance: More often than not, you will have to use additional classes (through inheritance) to extend the functionality of your Runnable object. Java does not support multiple inheritance, so it is much more convenient to create a new class which just implements Runnable (and allows to extend another class) than creating a new class that extends Thread and prevents you from inheriting anything else.

3. Runnable implementation and example

There are two ways to implement a Runnable in Java. Let’s take a quick look into them:

  • Inheritance: You can create a class which implements the Runnable interface. You will be forced to implement the run() method, which contains the logic/code of the task, and instantiate it in the standard Java way. You can use pass this as an argument to a Thread instance, as explained above.
  • Anonymous inner class: In some cases you need to run a small snippet of only a few lines of code. In that case, you can always create a new anonymous inner class inside the Thread constructor and implement the run() method there as well. This is of course not modular, and you cannot reuse that code.
Читайте также:  Unterminated string literal python ошибка

Let’s take a look at the code and see both of these ways at work!

Источник

Runnable with a Parameter

Well it’s been almost 9 years since I originally posted this and to be honest, Java has made a couple improvements since then. I’ll leave my original answer below, but there’s no need for people to do what is in it. 9 years ago, during code review I would have questioned why they did it and maybe approved it, maybe not. With modern lambdas available, it’s irresponsible to have such a highly voted answer recommending an antiquated approach (that, in all fairness, was dubious to begin with. ) In modern Java, that code review would be immediately rejected, and this would be suggested:

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

As before, details like handling that thread in a meaningful way is left as an exercise to the reader. But to put it bluntly, if you’re afraid of using lambdas, you should be even more afraid of multi-threaded systems.

Original answer, just because:

You can declare a class right in the method

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

Is there a way to pass parameters to a Runnable?

Simply a class that implements Runnable with constructor that accepts the parameter can do,

public class MyRunnable implements Runnable private Data data; 
public MyRunnable(Data _data) this.data = _data;
>

@override
public void run() .
>
>

You can just create an instance of the Runnable class with parameterized constructor.

MyRunnable obj = new MyRunnable(data);
handler.post(obj);

Parametrise a Runnable object at runtime

I suggest you change doSomething to a Consumer that accepts your parameters:

public void foo(ScheduledExecutorService execService) Consumer doSomething = (params) -> /*Code that I DON’T want to duplicate*/ 
/* small piece of code that I need to parametrise */
// use params
>;

// after someDelayInSeconds doSomething.run() will be called
YourParams asyncParams = /* parameters for async execution */;
execService.schedule(() -> doSomething.accept(asyncParams), someDelayInSeconds, TimeUnit.SECONDS);

// this might or might not call doSomething.run()
bar(doSomething);

>

private void bar(Consumer doSomething) if (/* some conditions are met */)
>

In the scheduled execution you then transform doSomething into a Runnable by passing the default parameters for asynchronous execution, while in bar() you pass the alternative parameters of your choice directly.

How can I pass a parameter to a Java Thread?

You need to pass the parameter in the constructor to the Runnable object:

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

Java: Parameterized Runnable

Typically you would implement Runnable or Callable with a class that supports a generic input parameter; e.g.

public class MyRunnable implements Runnable private final T t;

public MyRunnable(T t) this.t = t;
>

public void run() // Reference t.
>
>

Parameterized Runnable with function parameter

You can define an interface called TaskExecutor as follows :

public interface TaskExecutor public void execute(String log) 
>

You can then modify your ParameterizedTask class as follows :

public static class ParameterizedTask implements Runnable private String log; 
//other parameters

private TaskExecutor taskExecutor;

public ParameterizedTask(TaskExecutor taskExecutor) this.taskExecutor = taskExecutor;
>

@Override
public void run() taskExecutor.execute(log);
>
>

You can then define different behavior to be executed inside the run method as follows :

ParameterizedTask task = new ParameterizedTask(new TaskExecutor() < 
public void execute(String log) //doSomething with the log
>
>
);

Passing parameters to public void run() from the parent

Basically, you need to think in terms of passing the parameter to the Runnable object, not to the run() method.

If you make the anonymous class an inner class, it becomes pretty clear:

@Override
public void run()
String tmpVar;

// . (Some code)
// . (Some code)
// . (Some code)

Platform.runLater(new Updater(tmpVar));

// . (Some code)
// . (Some code)
// . (Some code)
>

// .

public static class Updater implements Runnable
private final String var ;

public Updater(String var) this.var = var ;
>

@Override
public void run()
// Access var here

for (int i=0; i <2000;i++)MyMainClass.leftPaneTextArea.appendText("Goodi!\n");
>

>
>

Now, if tmpVar is final , or «effectively final 1 «, then it will work with your anonymous inner class, and is basically translated to exactly the same thing as the inner class above (in other words, the anonymous inner class gets an implicit field which is populated with the value of the final variable):

@Override
public void run()
final String tmpVar = . ;

// . (Some code)
// . (Some code)
// . (Some code)

Platform.runLater(new Runnable() @Override public void run()
// access tmpVar here:

for (int i=0; i <2000;i++)
MyMainClass.leftPaneTextArea.appendText("Goodi!\n");
>

>
>);

// . (Some code)
// . (Some code)
// . (Some code)
>

The language designers could actually have made this work with non-final variables, but decided that the results would have been too confusing. What would happen would be that it would have been translated to the same inner class seen above: in other words the current value of tmpVar would have been implicitly passed to a field in the anonymous inner class. This would be a completely new variable, with a different scope, to the one it appears you are accessing, and its value would be a «snapshot» of the value of tmpVar at the time the anonymous inner class is created. Having what appears to be one variable that is actually referring to two different variables potentially with different values was deemed too confusing and bug-prone.

However, if tmpVar is not final (or effectively final): i.e. you are going to assign it values multiple times, you can explicitly «snapshot» the value of the variable:

@Override
public void run()
String tmpVar ;

// . (Some code)
// . (Some code)
// . (Some code)

final String varCopy = tmpVar ;

Platform.runLater(new Runnable() @Override public void run()
// access varCopy here:

for (int i=0; i <2000;i++)
MyMainClass.leftPaneTextArea.appendText("Goodi!\n");
>

>
>);

// . (Some code)
// . (Some code)
// . (Some code)
>

(1) «Effectively final» means that the variable is assigned a value exactly once. Equivalently, it means you could declare it final without creating any compilation errors.

Java Runnable as argument evaluation

I found a working solution for this problem, perhaps trivial for those coming from functional programming.

Accordingly to the example in last edit ([EDIT2])

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

public class TestEvaluation
public static void main(String[] args) throws InterruptedException
Middle middle = new Middle();

middle.register(new Consumer() @Override
public void accept(Values values) System.out.println("a is: " + values.getA());
System.out.println("b is: " + values.getB());
>
>);

Thread.sleep(2000);
>

static class Values
private int a = 0;
private int b = 0;

public int getA() return a;
>

public void setA(int a) this.a = a;
>

public int getB() return b;
>

public void setB(int b) this.b = b;
>
>

static class Middle
private ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(1);

public void register(Consumer passed)
Consumer middleConsumer = new Consumer() @Override
public void accept(Values values) System.out.println("Middle");
passed.accept(values);
>
>;

Leaf leaf = new Leaf(middleConsumer);
pool.schedule(leaf, 1, TimeUnit.SECONDS);
>
>

static class Leaf implements Runnable
public Consumer task;

public Leaf(Consumer task)
this.task = task;
>

@Override
public void run()
Values values = new Values();
values.setA(5);
values.setB(5);
System.out.println("Leaf");
task.accept(values);
>
>
>

This code produces the behavior i want.
Hope this will help someone.
Cheers!

Источник

Оцените статью