Getting the method that creates runnable from thread which runs the runnable - java

Suppose I have a custom Thread class which is responsible for running runnables
public class MyThread extends Thread{
public MyThread(Runnable r) {
super(r);
}
#Override
public void run() {
super.run(); // Can I put something here to get info about where the runnable is submitted from?
}
}
Then in some method, I submit the runnable
public void someMethod() {
new MyThread(new Runnable() {
#Override
public void run() {
System.out.println("Blah");
}
});
}
Suppose I have no control over someMethod, can I modify MyThread such that whenever a runnable is submitted to MyThread, I can get info about someMethod (e.g. method name someMethod, class name) ?
Edit
In fact the original question is part of my problem.
I am providing a ThreadFactory that can be used by a threadpool (ExecutorService).
public class MyThreadFactory implements ThreadFactory {
#Override
public Thread newThread(Runnable r) {
return new MyThread(r);
}
}
User can create a threadpool with MyThreadFactory
ExecutorService pool = Executors.newCachedThreadPool(new MyThreadFactory());
By calling pool.execute(runnable), a instance of MyThread will be created to perform the task specified by runnable. It is possible that the thread will be reused by multiple runnables. So I would like to retrieve Method and Class info in the public void run() method of MyThread. Since runnable is stored in a private field in the base Thread class, I cannot use a modified version of the solution provided by Laerte like:
#Override
public void run() {
super.run();
// Not working, Since MyThread cannot access private field target of Thread class
Method m = target.getClass().getEnclosingMethod();
System.out.println(m.toString());
}
Can I still obtain Method and Class about where the runnable is instantiated , at the moment public void run() is invoked?

To know things related to calling methods, class names, and so on, you should use reflection.
In your case, you should modify your code like this.
class MyThread extends Thread{
public MyThread(Runnable r) {
super(r);
Method m = r.getClass().getEnclosingMethod();
System.out.println(m.toString());
}
#Override
public void run() {
super.run();
}
}
The Method class will have the method reference. Using this call Method m = r.getClass().getEnclosingMethod();, you will receive the method that is enclosing the Runnable object. In your case, oneMethod.
That's the idea. Tell me if it helps.

Related

How to understand this detailed multithreading and anonymous class related code?

public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
System.out.println("hello");
}
})
{
public void run() {
System.out.println("world");
}
}.start();
}
Simply I get "world" with this. Why it can be written in this manner? What is the first run() method for?
This (contrived) code passes an instance of an anonymous Runnable class to an instance of an anonymous Thread class that overrides its usual implementation of run().
It's becomes (a little) clearer if you refactor it:
// The runnable instance
Runnable runnable = new Runnable() {
public void run() {
System.out.println("hello");
}
};
// Anonymous Thread class with a custom run() method
new Thread(runnable) {
public void run() {
System.out.println("world");
}
}.start();
The Runnable passed to the Thread, which would be executed by the thread's start() method, is ignored because the Thread object is also an instance of an anonymous class with a custom implementation of its run() method, which is hard-coded to print "world".
This code creates an instance of an anonymous sub-class of Thread and then starts that thread.
That sub-class overrides Thread's run() method with a method that prints "world".
The first run() method is part of an anonymous implementation of the Runnable interface which is passed to the constructor of the Thread instance. That implementation is ignored, since your Thread implementation overrides run().
The Runnable instance passed to the thread constructor is only executed (when the thread starts) if the Thread's run() method is not overridden.
The Thread class defines run() in this way :
#Override
public void run() {
if (target != null) {
target.run();
}
}
It invokes the run() method of the Runnable instance (target field of Thread)if this field is not null.
So when you create an anonymous class of Thread that overrides this method in this way:
new Thread(...) {
#Override
public void run() {
System.out.println("world");
}
}
The Thread run() method of the anonymous instance doesn't rely any longer on the target field to run the Runnable instance.
It execute only this code :
System.out.println("world");
So the Runnable instance passed to the constructor of Thread is totally ignored by run():
new Runnable() {
public void run() {
System.out.println("hello");
}
}
You have overridden the run method which prints hello with the one which prints world. This happened because in your code you have extended the Thread class with an anonymous class which overrode the run method, therefore the Runnable parameter's run is never called. You can update the code to use super.run() to call the runnable method from the original class.
Here is your code with the changes:
new Thread(new Runnable() {
public void run() {
System.out.println("hello");
}
}) {
public void run() {
super.run();
System.out.println("world");
}
}.start();

Unable to access global variables via Runnable in class

Good Day,
I have a class called FunctionHandler, that contains a method called evaluate like this:
class FunctionHandler{
Object globalVar;
public void Evaluate(){
ThreadPool pool;
Runnable task = new Runnable(){
public void run() { aWorkerTask(globalVar); }
}
pool.start(task);
pool.stop();
}
public void aWorkerTask(Object object){//worker stuff}
}
The problem is, my Runnable object can't seem to access globalVar! It seems to be it's own object somehow that can't reference what is inside it's class. Is there anyway around it?
The problem is that this code inherently doesnt work. Runnable cannot access globaVar. I need aWorkerTask to be wrapped in a Runnable and it needs access to globalVar
I'm not sure if this is the best implementation, but what I did was to create a class that implements Runnable as such:
public class MyRunnable implements Runnable {
private FunctionHandler functionHandler; //Global Reference - Only reading from it
private Object globalVar;
public MyRunnable(FunctionsHandler functionsHandler,Object globalVar) {
this.functionsHandler = functionsHandler;
this.globalVar = globalVar;
}
public void run(){
functionHandler.aWorkerTask(globalVar)
}
}
And pass in the main object functionHandler, which contains the function I need to make as a Runnable.
I then create a runnable as such:
MyRunnable taskProcessor = new MyRunnable(this,variableName,functionValues,jobNum.toString());
threadPool.runTask(taskProcessor);
A Runnable object is indeed its own object. Your options are to set it via a mutator or declare globalVar as final. Here's the mutator solution, in case you don't want globalVar to be final:
public void startRun() {
Object globalVar = new Object();
Runnable run = new Runnable() {
Object localVar;
public Runnable prepare(Object param) {
localVar = param;
return this;
}
#Override
public void run() {
/* Do your stuff */
}
}.prepare(globalVar);
}
Note that if you do this and you want globalVar to be modifiable both inside and outside the thread, you'll need to wrap it in a suitable dereferencing object.
If you want runnables to be able to access class variables, they have to be static; just change your code to:
static Object globalVar;

Callback from new thread to class from which thread was initiated

I have a class from which I am calling a new thread.
public class MainClass{
private void cleardata() {
// do something on a separate thread
new Thread(new Runnable() {
#Override
public void run() {
//Do Something
//After this I would like to notify my MainClass that some thing has been done and pass a value.
}
}
}
private void callbackFunc(int a){
// Do something based on value of a
}
}
I have a function in my MainClass. But how do i call this function from my new thread, so as to receive a callback.
Thanks.
You should just be able to call the method in MainClass by its name just as if you were calling from directly inside MainClass itself (as opposed to from the inner class).
If a method name you want to call happens to conflict with one that your inner class has inherited from Object then you can prefix the call with MainClass.this, e.g. MainClass.this.toString() calls toString on MainClass, whereas just toString() calls it on the inner class instance.
In such a case pass the instance of MainClass to the thread class ((during creation)) so that it can call method on it. Having inner class as suggested by others is also a good option.
Something similar-
class MainClass {
private void cleardata() {
new Thread(new MyThread(this)).start();
}
}
class MyThread implements Runnable {
private MainClass mc;
MyThread(MainClass mc) {
this.mc = mc;
}
public void run() {
// do something
// mc.someMethod();
}
}
public class MainClass{
private void cleardata() {
// do something on a separate thread
new Thread(new Runnable() {
#Override
public void run() {
callBackFunc(result);
}
}
}
private void callBackFunc(int a) {
}
}
Just do it:
public class MainClass{
private void cleardata() {
// do something on a separate thread
new Thread(new Runnable() {
#Override
public void run() {
//Do Something
notifyTheClass("a parameter");
}
}
private void notifyTheClass(String aParam) {
//..do something else
}
}
}
But it is not related to threads, this is about inner classes. If you want the main thread to wait until the new thread is finishes, use Futures for a result. Or use some other multithreading primitives.

Why does a java.lang.Thread not call the run() method of its explicit java.lang.Runnable when started?

The Java docs state that if we supplied a Runnable target when creating a new thread, .start() of that thread would run the run() method of the supplied runnable.
If that's the case, shouldn't this test code prints "a" (instead of printing "b") ?
public class test {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
System.out.println("a");
}
};
Thread t = new Thread(r) {
#Override
public void run() {
System.out.println("b");
}
};
t.start();
}
}
Because you are overriding Thread.run() method.
Here is the implementation of Thread.run():
#Override
public void run() {
if (target != null) {
target.run();
}
}
try:
}) {
#Override
public void run() {
super.run(); // ADD THIS LINE
System.out.println("b");
}
}.start();
You will get ab.
The default implementation is to call the Runnable. However you are overriding the default implementation and NOT calling the runnable. The simplest way to fix this is
new Thread(new Runnable() {
#Override
public void run() {
System.out.println("a");
}
}) {
#Override
public void run() {
super.run(); // call the default implementation.
System.out.println("b");
}
}.start();
The default implementation of Thread.run() does what the javadocs say (look at the source code)
public void run() {
if (target != null) {
target.run();
}
}
However, Thread.run() is public, and you overrode it, so it calls your println("b"), and totally ignores the Runnable passed in the constructor. Arguably, Thread.run() should be final, but it isn't.
You have overridden the default implementation of Thread.run() in what I guess is an anonymous subclass, hence what the JavaDoc says no longer applies.
If you try
public class Test {
public static void main(String[] args) {
new Thread(new Runnable() {
#Override
public void run() {
System.out.println("a");
}
}) .start();
}
}
You get the answer you expect, a.
The first block overrides run in Runnable. The second block overrides run in Thread. When you call start on a Thread, its run method is invoked. The default run method in Thread calls the Runnable.run method but since you overrode Thread.run there is no code to start the Runnable - only your code to print 'b'.
The documentation that I have says this:
"Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread."
which means that it should print b instead of a, since you have overridden the run() method of Thread.
You are calling start() method. Reading the docs in the link you provided it states:
public void start()
Causes this thread to begin execution; the Java
Virtual Machine calls the run method of this thread.
You should call the run() method if you would like to call the Runnable object's run method.
public void run() If this thread was constructed using a separate
Runnable run object, then that Runnable object's run method is called;
otherwise, this method does nothing and returns.
You are actually extending the Thread class and calling start on the instance of that anonymous subclass.
I think the confusion is that the "Java Doc" is for the java.lang.Thread class not for your class that extends that class.
e.g.
Runnable r = new Runnable() {
#Override
public void run() {
System.out.println("a");
}
};
Thread t = new Thread(r);
Now, if it does not call that run then java doc is wrong. Which is not true.

How to invoke two run methods in one java file

below is the code where i need to invoke 2 run methods for 2 different threads any way this can be done. please help on this.
public class QuestionList extends ListActivity implements Runnable {
//This below thread will call the run method
Thread thread = new Thread(QuestionList.this);
thread.start();
//can i have one more thread which call run1() method any idea
}
public void run() {
}
You cannot have two run() methods of course, and I suggest not using the same for both Threads (with a of if() statement to determine which behaviour to apply).
Instead you should create two distinct classes (why not inner classes) to implement these distinct behaviours. Something like:
public class QuestionList extends ListActivity {
class BehaviourA implements Runnable {
public void run() {
}
}
class BehaviourB implements Runnable {
public void run() {
}
}
private void somewhereElseInTheCode() {
BehaviourA anInstanceOfBehaviourA = new BehaviourA();
Thread threadA = new Thread(anInstanceOfBehaviourA);
threadA.start();
BehaviourB anInstanceOfBehaviourB = new BehaviourB();
Thread threadB = new Thread(anInstanceOfBehaviourB);
threadB.start();
}
}
The good thing with inner classes is that they can access to the members of QuestionList, and this seems to be what you are willing to do.
public class QuestionList extends ListActivity {
//This below thread will call the run method
Thread1 thread1 = new Thread(this);
thread1.start();
Thread2 thread2 = new Thread(this);
thread2.start();
}
class Thread1 implements Runnable
{
public void run() {
}
}
class Thread2 implements Runnable
{
public void run() {
}
}

Categories