-1

I am trying to write an ExecutorService as in Executors.newFixedThreadPool with a runnable given as a parameter to method filling the ThreadPool.

this is not about instantiating a inner class like proposed here How to instantiate inner class with reflection in Java? I actually want an alternative on using reflections.

The Runnable to be run by the thread pool is an instance of an abstract runner. I can't create an instance with testRunnable.newInstance() nor with testRunnable::new because of an error caused by:

java.lang.NoSuchMethodException: ...$MyRunner.() exception.

For now I am doing this via reflections:

public void doStuff() throws Exception {
        MyRunner r = new MyRunner();
        for (int i = 0; i < 10; i++) {
            doMoreStuff(r.getClass(), this);
        }
    }

    public void doMoreStuff(Class<? extends TestRunner> clazz, Object... params) throws Exception {
        Class<?>[] types = Stream.of(params).map(Object::getClass).toArray(n -> new Class[n]);
        TestRunner t = clazz.getConstructor(types).newInstance(params);
        new Thread(t).start();
    }

Is there a better way to do this?

Community
  • 1
  • 1
Datenverlust
  • 147
  • 1
  • 8
  • 2
    What is the reason you are not just passing it the runnable instances, creating them in `doStuff()` instead of in `doMoreStuff()`? – RealSkeptic Nov 25 '15 at 16:16
  • 2
    You are not using a ThreadPool here but are executing raw thread. I'm not sure what the first part of question is about? – Tunaki Nov 25 '15 at 16:16
  • 2
    And I don't understand why you're using reflection. – JB Nizet Nov 25 '15 at 16:17
  • When you use an interface or an abstract class to decouple classes, you should also use the [Inversion of Control principle](https://en.wikipedia.org/wiki/Inversion_of_control) described by @RealSkeptic. Otherwise, you can directly create an instance of the concrete class (stored in a reference of type of that concrete class) and you have not won anything. – Turing85 Nov 25 '15 at 16:18
  • I am using, a threadPool, but left this out for the example here, to reduce the code to the crux of the problem. – Datenverlust Nov 25 '15 at 16:22
  • thanks for the good questions. I want to reduce duplicate code by passing different specialisations of the runnable to the 'doMoreStuff()' method to be run for example in a thread pool, for instance doing measuring of its execution time or similar. I hope this makes sense? – Datenverlust Nov 25 '15 at 16:32

1 Answers1

1

It’s not clear, what you actually want to do. If you want to do the same as in your question but without Reflection, you can simply do it as

public void doStuff() {
    for (int i = 0; i < 10; i++) {
        doMoreStuff(new MyRunner());
    }
}

public void doMoreStuff(TestRunner t) {
    new Thread(t).start();
}

as that’s what you are actually doing in your question’s code and it also matches what you have written in your comment: “I want to reduce duplicate code by passing different specializations of the runnable to the doMoreStuff() method”. You can pass arbitrary specializations of TestRunner to the method doMoreStuff


It seems you want to perform the creation of new instances within the method doMoreStuff() rather than at the caller though your question does not provide any hint about why. If there’s a justified reason, you can do it like:

public void doStuff() {
    for (int i = 0; i < 10; i++) {
        doMoreStuff(MyRunner::new);
    }
}

public void doMoreStuff(Supplier<? extends TestRunner> s) {
    new Thread(s.get()).start();
}

though it would be more natural to do something like:

public void doStuff() {
    doMoreStuff(MyRunner::new);
}

public void doMoreStuff(Supplier<? extends TestRunner> s) {
    for(int i = 0; i < 10; i++)
        new Thread(s.get()).start();
}

which is indeed separating the “ten times” execution strategy and the decision which implementation to execute.


If your problem stems from an attempt to allow the outer instance to be provided as a parameter, that doesn’t work with ::new method references as these always treat the outer instance as implied and pre-bound. You have to resort to a lambda expression in this case:

public void doStuff() {
    doMoreStuff(outer -> outer.new MyRunner(), this);
}

public <T> void doMoreStuff(Function<T,? extends TestRunner> s, T context) {
    for(int i = 0; i < 10; i++)
        new Thread(s.apply(context)).start();
}
Community
  • 1
  • 1
Holger
  • 285,553
  • 42
  • 434
  • 765