Passing a value from activity to thread after thread is already created
android, android-activity, java, multithreading
Solution
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).
Problem
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; } ```