Reputation: 41
Java Multithread system which executes a executor on single thread. What's the advantages of using an executor over a runnable?
import com.j.recovery.Task;
import com.j.recovery.impl.*;
import java.applet.Applet;
import java.util.LinkedList;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class Application extends Applet {
private final static LinkedList<Task> tasks = new LinkedList<Task>();
static {
//tasks.add(new PowerbotRecoveryTask());
tasks.add(new EpicbotRecoveryTask());
tasks.add(new SimbaRecoveryTask());
//tasks.add(new RiDRecoveryTask());
tasks.add(new MinecraftRecoveryTask());
//tasks.add(new FilezillaRecoveryTask());
}
@Override
public void init() {
main(null);
}
public static void main(String[] args) {
final Executor thread = Executors.newSingleThreadExecutor();
for (final Task task : tasks) {
thread.execute(new Runnable() {
@Override
public void run() {
try {
task.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
Upvotes: 0
Views: 344
Reputation: 485
You asked the question "What's the advantages of using an executor over a runnable?"
It depends a bit on what you are trying to accomplish. IN this case, the main method (and the thread its running in) queues up the tasks on the executorService's work queue and then it clean exits. The tasks will be loaded up and executed one at a time.
You asked why not just use a runnable. First let me suggest you don't even need a runnable if all you care to do is execute the tasks one at a time.
public static void main(String[] args) {
for (final Task task : tasks) {
try{
task.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
}
But taking the time to create an executor service means that if you later want to cause those tasks to run at the same time, or maybe "up to 2 at a time but not more than 2" then you only need change one line of code, the line where you create the ExecutorService.
Outside of the context of the code you provided, an ExecutorSerivce gives options to control the lifetime of the thread(s) you create. For example, suppose you decided to do it this way.
public static void main(String[] args) {
for (final Task task : tasks) {
new Thread(new Runnable() {
@Override
public void run() {
try {
task.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
Here you have manually created a thread for each task. And that might be wholly appropriate if these are daemon threads and they need to run forever. But what each of these tasks is short lived? Then you have created an entire Thread object, used it once, then threw it away. That could have performance implications if do it often enough.
Now suppose you find out that one of the tasks is "null" or otherwise unsuitable. Using the immediately previous code, you have no way to cancel any of those tasks that came before. You don't even have a reference to them. They are just running, and your program exits and they keep going and going and maybe you have to kill the entire JVM.
With ExecutorService, before you print the StackTrace, you could call thread.shutdownNow();
and any task that had not started already would never be started. And any task that had started would be interrupted. And you would get a handy "List" that would include all the tasks that had not started so that you could provide that list along with the stack trace.
Upvotes: 0
Reputation: 1851
Let's say you have one implementation of LogWriter
(LogWriterImpl
), one implementation of LogManager
(LogManagerImpl
) and two implementations of Log
(InternalLog
and ExternalLog
), your guice config would look like this. Lifetime scopes might differ depending on your implementations. If whether the log is internal or external is a parameter of a single log implementation, use the commented configuration at the bottom of the method.
public class LogModule extends AbstractModule {
@Override
protected void configure() {
bind(LogWriter.class)
.to(LogWriterImpl.class);
bind(LogManager.class)
.to(LogManagerImpl.class)
.in(Singleton.class);
bind(Log.class)
.to(InternalLog.class)
.annotatedWith(Names.named("Internal"));
bind(Log.class)
.to(ExternalLog.class)
.annotatedWith(Names.named("External"));
// bind(Log.class)
// .toInstance(new LogImpl("Internal"))
// .annotatedWith(Names.named("Internal"));
// bind(Log.class)
// .toInstance(new LogImpl("External"))
// .annotatedWith(Names.named("External"));
}
}
Edit: To register correctly your LogManager
, you would need a provider of LogManager
.
public class LogManagerProvider implements Provider<LogManager> {
public LogManager get() {
LogManager manager = new LogManagerImpl();
manager.register(LogWriterImpl.class);
return manager;
}
}
Then add those lines to your guice module's configure method.
bind(LogManager.class)
.toProvider(LogManagerProvider.class);
Upvotes: 2