edoardotognoni
edoardotognoni

Reputation: 2752

wakelock inside a running thread Android

I have this simple question:

In a service i need to run 2 more threads independent from each other, and i need a wakelock to let them be executed. I give you an example:

   wl.aquire();

    if (true) {
        mExecutorService.execute(thread1);
    }

    if (true) {
        mExecutorService.execute(thread2);
    }
   wl.release();

So, in this case, the wake lock will be released once the 2 threads have started or does it wait for them to finish?

If not, i need the wakelock to stay up while they're running, and release it only when the last thread has finished. How can i do that? Do i have to acquire new wakelocks inside the thread's body?

Thank you

Upvotes: 2

Views: 2522

Answers (3)

Logan Pickup
Logan Pickup

Reputation: 2374

See http://developer.android.com/reference/android/os/PowerManager.WakeLock.html -- the correct way would be to acquire the wakelocks inside the two threads you are running. Given your example code, you will need a member variable inside thread1 and thread2 to store the wakelock, and some way to pass the wakelock in, perhaps like this:

thread1.setWakelock(wl);
thread2.setWakelock(wl);

class Thread implements Runnable {
    PowerManager.Wakelock mWakelock;
    void setWakelock(PowerManager.Wakelock wl) {
        mWakelock = wl;
    }
}

Then inside thread1 and thread2, you will need:

run() {
    mWakelock.acquire();
    ... your existing code here ...
    mWakelock.release();
}

Note that this will work since wake locks are reference counted by default; see PowerManager.WakeLock.setReferenceCounted().

Waiting for the threads to finish using thread.join() is wrong; it will block the UI thread and you will get an ANR, as you found out.

Upvotes: 0

Wilhem Meignan
Wilhem Meignan

Reputation: 464

According to the Executor execute() documentation: "Executes the given command at some time in the future. The command may execute in a new thread, in a pooled thread, or in the calling thread, at the discretion of the Executor implementation."

So it depends on which concrete Executor you are using.

I think you are supposed to use submit() to give a new job to an Executor.

If you stick with the Executor, calling get() on the Future returned by submit() will block until the result is available.

So you could call:

Future<Result> result_1 = mExecutorService.execute(Runnable1);
Future<Result> result_2 = mExecutorService.execute(Runnable2);

result_1.get();
result_2.get();

Alternatively, you could start two threads and wait for them to finish:

Thread t1 = new Thread(Runnable1);
Thread t2 = new Thread(Runnable2);
t1.start();
t2.start();

t1.join();
t2.join();

Hope this helps.

Upvotes: 4

Praful Bhatnagar
Praful Bhatnagar

Reputation: 7435

Assuming you are running this code from AsyncTask or background thread. You can call [Thread.join()] on all the threads before the call to wl.release();

check out this link for join() detail

EDIT1: on executor you can also use awaitTermination() with long wait value to wait for it to finish all the tasks. Following code is from the official java doc:

void shutdownAndAwaitTermination(ExecutorService pool) {
   pool.shutdown(); // Disable new tasks from being submitted
   try {
     // Wait a while for existing tasks to terminate
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
       pool.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     }
   } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     pool.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();
   }
 }

Upvotes: 1

Related Questions