0

I have a Java-based app (Android) and I'd like to be able to perform potentially long operations in the background. The Android docs on AsyncTask advise against using them for tasks that may run for more than a few seconds (why is this?) so I'm using a subclass of Java's Thread instead. The goal of this Thread subclass (HPCHeadThread) is mainly to host the instances of a few asynchronous control mechanisms, and provide accessor methods to said mechanisms for other threads to use. The workflow I'm aiming for is to be able to call hHPCHeadThread.doStuff() from any thread with a reference to HPCHeadThread, and have the control objects instantiated in HPCHeadThread do work on the HPCHeadThread thread and only on that thread. When not being accessed by another thread, HPCHeadThread should sleep so as not to waste CPU cycles. I launch the peripheral thread HPCHeadThread from the main thread (TestActivity) like so:

TestActivity.java

//..snip
private HPCHeadThread hHPCHeadThread;

@Override
protected void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  //...snip 

  //Create and start our HPCHeadThread
  hHPCHeadThread = HPCHeadThread.getHPCThreadHead();
  hHPCHeadThread.start();

  //..snip
}

HPCHeadThread.java

//..snip
public class HPCHeadThread extends Thread {
  private static volatile HPCHeadThread instance;
  private static boolean bIsActive = true;


  private HPCHeadThread(){
    super();        
  }

  public static HPCHeadThread getHPCThreadHead(){

    if(instance == null && bIsActive){
      instance = new HPCHeadThread();   
    }

    return instance;

  }


  public void safeStop(){
    instance = null;
    bIsActive = false;
  }

  @Override
  public void run(){
  Thread thisThread = Thread.currentThread();
  Thread.currentThread().setName("HPC_Head_Thread");

  while(instance == thisThread){
    //Our HPCHeadThread 'main' loop
    //Try to have it sleep whenever it isn't being used
    //Hopefully it will wake nicely upon attempted access,
    //perform the desired function, and then return to sleep


      try{
        Thread.sleep(10000);
      }
      catch (InterruptedException e){
        //e.printStackTrace();
      }

    }//End while
  }//End Run()

  public void doStuff(){
    //..snip stuff..
  }

}

Now if I invoke hHPCHeadThread.doStuff() from within my main TestActivity thread, does the work process on HPCHeadThread or on the main TestActivity thread? Does TestActivity wait for the doStuff() method to return before continuing sequential execution within its own thread? Do method invocations wake HPCHeadThread and/or do they cause an InterruptedException to be thrown in HPCHeadThread's run() method while loop?

CCJ
  • 1,619
  • 26
  • 41
  • Don't sleep randomly waking when you think it's time to do work. Use a queue or something... Sounds like you don't have enough experience with Java concurrency (memory model etc), so you're going to end up in hell if you introduce too much concurrency. – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ Mar 29 '13 at 16:13
  • @Longpoke "Use a queue or something" care to elaborate, please? It is true that I am somewhat new to Java concurrency; I've read the official docs and still have the questions above. What would be a better way to handle the sleep/wake cycle of a peripheral thread like the one above, which expects to be needed infrequently (and not at determined intervals) and may require some significant processing time when it is needed? To me it seemed to make the most sense to always have it sleeping unless it is called by another thread, but Java requires a wake interval so I chose 10 seconds for now – CCJ Mar 29 '13 at 16:26
  • would a wait-notify pairing might make more sense, for instance having TestActivity invoke a synchronized method in HPCHeadThread to get a lock on its monitor, then call hHPCHeadThread.wait() right after start() and then later notify() before doStuff() followed by wait() again? – CCJ Mar 29 '13 at 16:32
  • Hmm, http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html would seem to indicate that I have the monitor-wait-notify shuffle wrong... looks like I'd need a separate object whose monitor would hold HPCHeadThread in its wait set whenever it wasn't needed, etc. Might be worth looking into for optimal CPU performance, but in the meantime, my questions in the post are more pressing than proper sleep/wake wait/notify handling... – CCJ Mar 29 '13 at 16:37
  • 1
    wait/notify stuff could work. A queue does this for you though, any thread can add to the queue at any time, and the working thread just calls queue.take() which returns the next job item on the queue (waiting if there is none). I believe `LinkedBlockingQueue` provides this functionality. Also be aware that Java's concurrency model is almost as weak as C; there is memory reordering/memory (in)visibility etc. The classes in the concurrent package generally provide guarantees against these types of hazards. – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ Mar 29 '13 at 16:39
  • 1
    I would like to explain why you shouldn't do long running operations in an AsyncTask. Since Android 3 or so the thread pool of AsyncTask contains only one thread. The goal is to eliminate concurrency bugs. So if you do a long running operation in one AsyncTask all others will have to wait for its termination. For more info read the "Order of execution" chapter here: http://developer.android.com/reference/android/os/AsyncTask.html – Kirill Rakhman Mar 29 '13 at 18:26

2 Answers2

2

The Android documentation advices against long running threads in activities because activities can be swapped out any time the system needs memory and the app is running in the background.

If you want to do long running tasks: create a Service which is intended for just that: long running tasks that should not be thrown out of when more memory is needed.

On the queue thing: sounds like a good advice. Just use a ArrayBlockingQueue which has a blocking call: take()

Create your workerthread and queue like this:

public class Workqueue implements Runnable {


private static Workqueue theInstance=null;

public static synchronized Workqueue getInstance(){
   if(theInstance==null){
       theInstance=new WorkQueue();
     }
  return theInstance;
  }


private ArrayBlockingQueue<Runnable> queue=new ArrayBlockingQueue<Runnable>();
private Thread workerThread;

private WorkQueue(){
    workerThread=new Thread(this);
    workerThread.start();
}


public void run(){
   while(keepRunning){
      //pick up next task or wait (not using any cpu cycles)
      Runnable r=queue.take();
      //execute task
      r.run();
    }
}

public void addTask(Runnable task){
   queue.add(task);
}

Usage would be:

Runnable newTask= new Runnable(){
public void run(){
   dostuff...
}};
Workqueue.getInstance().addTask(newTask);

This can be called from any thread without blocking it, it adds tasks to the queue which will be executed one by one.

bluevoid
  • 1,274
  • 13
  • 29
  • Ah,very nice. One addendum however, a LinkedBlockingQueue might serve better here as it is unbounded. ArrayBlockingQueue is backed up automatically by a bounded array which can be handy when you know your set bounds, but in this case we prefer no bounds – CCJ Mar 29 '13 at 22:01
  • LinkedBlockingQueue allows you to not specify what should happen if more than x tasks are waiting, but are you sure that is what you want? More than 50 jobs is probably an error -> using ArrayBlockingQueue forces you to think and implement what should happen when there are too many jobs. – bluevoid Mar 30 '13 at 12:32
0

First, I think you can use the old Singleton design pattern to accomplish having one thread accessible from everywhere. It would look something like:

public class MyThread extends Thread () {
  private static MyThread _me;

  private MyThread() { /* make constructors private it can only be made by getting an instance */ }

  public static MyThread getInstance() {
    if(_me == null) {
      _me = new MyThread();
    }
    return _me;
  }
}

Second, calling doStuff() will run in the calling thread. In a Java Thread, all the Thread's processing happenins in the run() method.

Last, you may want to look at implementing wait and notify, or timed waits if the Thread doesn't need to execute immediately.

CodeChimp
  • 8,016
  • 5
  • 41
  • 79
  • You could also **not** use the singleton pattern, thus avoiding all the concurrency nightmares associated with it. If you instantiate the object yourself it's a lot less likely to run into memory re-ordering problems. – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ Mar 29 '13 at 16:40
  • Aha, this explains the odd behavior I was seeing... all the separate functionality occurs in run(), eh? I suppose a fair way to centralize everything would be to change HPCHeadThread into a ThreadFactory of sorts, producing and launching Runnable implementations tailored for each type of work I want to go on in the background – CCJ Mar 29 '13 at 16:54
  • 1
    @Longpoke what is memory re-ordering, and what sort of problems are you referring to here? – CCJ Mar 29 '13 at 16:54
  • @CCJ He is referring to this: http://assylias.wordpress.com/2013/02/01/java-memory-model-and-reordering/ – CodeChimp Mar 29 '13 at 17:18
  • @CGJ: Here is a simple example. Say thread `A` starts thread `B`, then waits (by polling) for global variable `done` to be `true`. All thread `B` does is sets `done` to `true`. There is no guarantee that `A` ever sees that `done = true`, so thread `A` just gets stuck forever. Here is some code demonstrating this: http://ideone.com/wIUIT1 The code worked on this website, but on my machine it sits in a loop forever. – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ Mar 29 '13 at 17:21
  • @Longpoke In your example you link too, the code will never set the done to true because the thread is never interrupted, thus the exception never happens. You effectively said "while(true)". I don't see how that relates to the simple Singleton example I showed (granted, probably needs a sync block around the creation part). I do feel there are better patterns, like maybe having a reverse pub/sub, but the OP was asking specifically about threading. – CodeChimp Mar 29 '13 at 17:51
  • @CodeChimp: Look at this example: http://ideone.com/JEFzjL On my machine, it prints "set done to true", but never prints "main thread done", instead it sits consuming 100% CPU forever. Concurrent singletons make much worse problems than this lol... – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ Mar 29 '13 at 18:07
  • @Longpoke That one looks a LOT different than the first one you posted. However, I ran this about 100 times (out of Eclipse), and it never once broke. That said, I would expect to see some sync blocks and at least a timed wait. It just good practice to do these things when you are dealing with concurrent threads. – CodeChimp Mar 29 '13 at 18:32
  • @CodeChimp: they are the same, I just added prints to the second one, so you can see more clearly what's happening. (I just noticed the original version had the `done=true` indented, so it looked like it was in the exception handler, but it was not) it's true that locking a monitor happens-before unlocking a monitor. so if there was a lock used by both threads around accessing the `done` variable, my code would not be broken. the only problem with locks is that they are prone to deadlocks, which tends to happen with mutually dependent code (which tends to happen in code that has singletons) – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ Mar 29 '13 at 18:43
  • @CodeChimp: See http://stackoverflow.com/questions/4934913/are-static-variables-shared-between-threads – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ Mar 29 '13 at 18:50
  • So can this issue be resolved by marking (in your ideone example) the 'done' boolean variable or (in the singleton pattern above) _me MyThread variable volatile? – CCJ Mar 29 '13 at 20:30
  • @CodeChimp if _me from the above post was marked volatile, would a double-checked locking idiom (or any idiom using the synchronized method/statement) be necessary? If so, why? It seems that volatile (post JDK5) should be enough to guarantee a working singleton access in a multithreaded context – CCJ Mar 29 '13 at 22:41