In my android program an Activity calls a new surface view class, which then in turn calls a new thread class. I want to be able to pass a value to the thread class from the activity's onPause and onResume methods, so I can pause and resume the thread. The only way I know to pass this data is by creating a new instance, which would just create a different thread. How should I go about this without creating a new thread instance?
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new GameSurface(this));
}
@Override
protected void onResume() {
super.onResume();
//Would like to pass this value
int state = 1;
}
@Override
protected void onPause() {
super.onPause();
//Would like to pass this value
int state = 2;
}
There are two main ways to return values from a thread, they are: Extend threading. Thread and store data in instance variables. Store data in global variables.
Once a thread in the thread pool completes its task, it's returned to a queue of waiting threads. From this moment it can be reused. This reuse enables applications to avoid the cost of creating a new thread for each task.
A race condition occurs when two threads access a shared variable at the same time. The first thread reads the variable, and the second thread reads the same value from the variable.
Threads do not really have return values. However, if you create a delegate, you can invoke it asynchronously via the BeginInvoke method. This will execute the method on a thread pool thread. You can get any return value from such as call via EndInvoke .
A little background on concurrency
Passing values in concurrency is the easy part. Look into the AtomicInteger
data type (More information here). Atomicity also means All or nothing
. This data type isn't necessarily sending data between threads or processors (like you would with mpi
) but it is merely sharing data on its shared memory.
But what is an Atomic Action?....
An atomic operation is an operation which is performed as a single unit of work without the possibility of interference from other operations.
In Java the language specification guarantees that reading or writing a variable is atomic (unless the variable is of type long or double). Long and double are only atomic if they declared as volatile....
Credit(Java Concurrency / Multithreading - Tutorial by Lars Vogel)
I highly recommend you read this, it covers everything from atomicity
, thread pools
, deadlocks
and the "volatile" and "synchronized" keyword
.
Start Class This will execute a new thread (It can also be referred to as our Main Thread
).
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author Michael Jones
* @description Main Thread
*/
public class start {
private AtomicInteger state;
private Thread p;
private Thread r;
/**
* constructor
* initialize the declared threads
*/
public start(){
//initialize the state
this.state = new AtomicInteger(0);
//initialize the threads r and p
this.r = new Thread(new action("resume", state));
this.p = new Thread(new action("pause", state));
} //close constructor
/**
* Start the threads
* @throws InterruptedException
*/
public void startThreads() throws InterruptedException{
if(!this.r.isAlive()){
r.start(); //start r
}
if(!this.p.isAlive()){
Thread.sleep(1000); //wait a little (wait for r to update)...
p.start(); //start p
}
} //close startThreads
/**
* This method starts the main thread
* @param args
*/
public static void main(String[] args) {
//call the constructor of this class
start s = new start();
//try the code
try {
s.startThreads();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //start the threads
} //close main
} //close class start
Because the integer is atomic, you can also retrieve it anywhere but the main method
in the Start Class with System.out.println("[run start] current state is... "+state.intValue());
. (If you wish to retrieve it from the main method
, you will have to setup a Setter/Getter, like I've done so in the Action Class)
Action Class This is our thread in action (It can also be referred to as our Slave Thread
).
import java.lang.Thread.State;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author Michael Jones
* @description Slave Thread
*/
public class action implements Runnable {
private String event = "";
private AtomicInteger state;
/**
* The constructor (this represents the current instance of a thread).
*
* @param event
* @param state
*/
public action(String event, AtomicInteger state) {
this.event = event; // update this instance of event
this.state = state; // update this instance of state
} // constructor
/**
* This method will be called after YourThreadName.Start();
*/
@Override
public void run() {
if (this.event == "resume") {
this.OnResume(); // call resume
} else {
this.OnPause(); // call pause
}
} // close Runnable run() method
/**
* The resume function Use the auto lock from synchronized
*/
public synchronized void OnResume() {
System.out.println("[OnResume] The state was.." + this.getAtomicState()
+ " // Thread: " + Thread.currentThread().getId());
this.setAtomicState(2); // change the state
System.out.println("[OnResume] The state is.." + this.getAtomicState()
+ " // Thread: " + Thread.currentThread().getId());
} // close function
/**
* The pause function Use the auto lock from synchronized
*/
public synchronized void OnPause() {
System.out.println("[OnPause] The state was.." + this.getAtomicState()
+ " // Thread: " + Thread.currentThread().getId());
this.setAtomicState(1); // change the state
System.out.println("[OnPause] The state is.." + this.getAtomicState()
+ " // Thread: " + Thread.currentThread().getId());
} // close function
/**
* Get the atomic integer from memory
*
* @return Integer
*/
private Integer getAtomicState() {
return state.intValue();
}// close function
/**
* Update or Create a new atomic integer
*
* @param value
*/
private void setAtomicState(Integer value) {
if (this.state == null) {
state = new AtomicInteger(value);
} else
state.set(value);
} // close function
} // close the class
The Console Output
[OnResume] The state was..0 // Thread: 9
[OnResume] The state is..2 // Thread: 9
[OnPause] The state was..2 // Thread: 10
[OnPause] The state is..1 // Thread: 10
As you can see, the AtomicInteger state
is being shared in the memory between our threads r
and p
.
Solution and Things to look for...
The only thing you have to watch when doing concurrency is Race Conditions
/Deadlocks
/Livelocks
. Some RaceConditions
occur because Threads
are created in random order (And most programmers think in the mind set of sequential order).
I have the line Thread.sleep(1000);
so that my Main Thread
gives the slave thread r
a little time to update the state
(before allowing p
to run), due to the random order of threads.
1) Keep a reference to the thread and pass the value with a method. Credit (SJuan76, 2012)
In the solution I've posted I make my Main Thread
(aka class start
) as my main communicator to keep track of the Atomic Integer
for my slaves to use (aka class action
). My main thread is also updating
the memory buffer
for the Atomic Integer
on my slaves (The update on the memory buffer occurs in the background of the application and is handled by the AtomicInteger
class).
1) Keep a reference to the thread and pass the value with a method.
2) During the thread creation, pass it an object shared with the Activity. Put the values to pass into the object, have the thread check it regularly until the values are found.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With