patternjavaMajor
Run different methods in background threads without duplication
Viewed 0 times
withoutbackgroundthreadsduplicationmethodsdifferentrun
Problem
In my Android app I have number of methods that should be executed in a background thread.
One of the methods looks like this
As you can see, there are some code that only ensures an eligible thread is used.
How can I avoid copying this "threading" code over and over for each method that should be run in a background thread?
One of the methods looks like this
public static void processItem(final Context context, final String itemId)
{
if (Looper.myLooper() == Looper.getMainLooper())
{
Thread task = new Thread()
{
@Override
public void run()
{
processItem(context, playlistId);
}
};
task.start();
return;
}
// actual processing
}As you can see, there are some code that only ensures an eligible thread is used.
How can I avoid copying this "threading" code over and over for each method that should be run in a background thread?
Solution
Extending Thread is an 'anti-pattern' in Java. The right way to do this work is to create an instance of a Runnable, and use the runnable as a constructor to a Thread instance.
But, and this is a big "but", in Java, in general, the practice of creating and using threads like this is being replaced by frameworks that manage the threads in a better way. In regular Java, you should be using the Executor, ExecutorService, and Executors class in the concurrent package.
As for android-specific use cases, you should read up on the threading models in Android paying special attention to the AsyncTask in Android dev kit
Update: more about the Thread anti-pattern
Jon Skeet says so ... ;-) and most people agree. What you have is something that needs to be done. That is what you need to implement, the way to do it. The place to run that something is on a thread. You do not implement the thread, you implement the task. There are two different concepts here: what needs to be done, and where it needs to be done. You are only implementing one of those.
Update: alternative solution
To reduce the logic required for managing the thread the code runs on, I would do one of two things:
-
Have a common utility method that looks something like:
and then you can call it in your method with:
Thread t = new Thread(new Runnable() {
public void run() {
/*
* Do something
*/
}
});
t.start();But, and this is a big "but", in Java, in general, the practice of creating and using threads like this is being replaced by frameworks that manage the threads in a better way. In regular Java, you should be using the Executor, ExecutorService, and Executors class in the concurrent package.
As for android-specific use cases, you should read up on the threading models in Android paying special attention to the AsyncTask in Android dev kit
Update: more about the Thread anti-pattern
Jon Skeet says so ... ;-) and most people agree. What you have is something that needs to be done. That is what you need to implement, the way to do it. The place to run that something is on a thread. You do not implement the thread, you implement the task. There are two different concepts here: what needs to be done, and where it needs to be done. You are only implementing one of those.
Update: alternative solution
To reduce the logic required for managing the thread the code runs on, I would do one of two things:
- simply always use a different thread. Simply remove the if-condition and do all the processing in a Runnable's run method.
-
Have a common utility method that looks something like:
private static final ExecutorService THREADPOOL = Executors.cachedThreadPool();
public static void runButNotOn(Runnable toRun, Thread notOn) {
if (Thread.currentThread() == notOn) {
THREADPOOL.submit(toRun);
} else {
toRun.run();
}
}and then you can call it in your method with:
private static void processImplementation(final Context context, final String itemId) {
// ... the actual work.
}
public static void processItem(final Context context, final String itemId) {
Runnable task = new Runnable(){
public void run() {
processImplementation(context, itemId);
}
};
runButNotOn(task, Looper.getMainLooper().getThread());
}Code Snippets
Thread t = new Thread(new Runnable() {
public void run() {
/*
* Do something
*/
}
});
t.start();private static final ExecutorService THREADPOOL = Executors.cachedThreadPool();
public static void runButNotOn(Runnable toRun, Thread notOn) {
if (Thread.currentThread() == notOn) {
THREADPOOL.submit(toRun);
} else {
toRun.run();
}
}private static void processImplementation(final Context context, final String itemId) {
// ... the actual work.
}
public static void processItem(final Context context, final String itemId) {
Runnable task = new Runnable(){
public void run() {
processImplementation(context, itemId);
}
};
runButNotOn(task, Looper.getMainLooper().getThread());
}Context
StackExchange Code Review Q#56428, answer score: 21
Revisions (0)
No revisions yet.