Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a value from activity to thread after thread is already created

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;
}
like image 670
zkello Avatar asked Jul 21 '12 23:07

zkello


People also ask

How do you return a value from a thread?

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.

When using a thread pool What happens to a given thread after it finishes it task?

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.

What happens when two threads access same variable?

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.

Can a thread return a value C#?

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 .


2 Answers

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).

like image 116
16 revs, 2 users 74% Avatar answered Nov 10 '22 23:11

16 revs, 2 users 74%


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.

like image 30
SJuan76 Avatar answered Nov 10 '22 22:11

SJuan76