0

I created two threads in main activity to manipulate shared field member but value seems not updated by threads, because variable's value is same, actually im practicing synchronization, here is my code:

public class ActMain extends Activity {

Handler handler;
Integer THREAD_COUNTER = 10;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_act_main);

    Message m = new Message();
    Bundle b = new Bundle();
    b.putInt("what", 5);
    m.setData(b);


    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            for(int i =0; i < 10; i++){
                add();
            }

        }
    });

    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            for(int i = 0; i < 30; i++){
                subtract();
            }

        }
    });

    t1.start();
    t2.start();

    Log.i("MainActivity " , " thread counter" + THREAD_COUNTER);
     //same value 10 of THREAD_COUNTER
blackHawk
  • 6,047
  • 13
  • 57
  • 100

2 Answers2

1

I created two threads in main activity to manipulate shared field member but value seems not updated by threads...

There are a couple of problems with your code. First off, you start 2 threads and then immediately log the result. It is likely that the threads have actually not started running by the time the Log.i(...) line executes. To wait for the background threads to finish you need to use join():

t1.start();
t2.start();
// t1 and t2 start running in the background but we need to wait for them to finish
t1.join();
t2.join();
Log.i(...);

Another problem is that you can't just add and subtract on the THREAD_COUNTER integer from 2 threads. Threads get their performance from working on local cached memory so anytime threads are sharing information, you need to worry about locking and memory synchronization so they can coordinate their updates.

With integers in a multi-threaded environment, Java gives us the AtomicInteger class which is a great way for threads to concurrently update an integer value. So your code should be something like:

// initialize our shared counter to 10
final AtomicInteger threadCounter = new AtomicInteger(10);
// ...
// to add:
threadCounter.addAndGet(5);
// to subtract:
threadCounter.addAndGet(-7);
// ...
// to get the value after the joins
threadCounter.get();

Couple other comments:

  • All caps fields are constants. threadCounter instead of THREAD_COUNTER.
  • Always use int instead of Integer unless the value can be null.
  • Not sure if you did this but never call synchronized on a value that can change like an Integer or Boolean. You must synchronize on a constant object instance adding something to Integer changes the object so multiple threads will be locking on different objects. It is a good pattern to always call synchronized on a private final field.
Gray
  • 115,027
  • 24
  • 293
  • 354
  • It means we can instruct other thread to wait until first thread completes with join and then start execution, also we are also forcing log to only show when second thread completes when we do t2.join(); are we pausing main thread? – blackHawk May 29 '17 at 17:46
  • Also first i did t1.join and then log1 then t2.join then log2, sometimes i get right execution t1->log1->t2->log2 and sometimes t1->t2->log1->log2, why is it happening, also sometimes t2->t1->log1->log2 – blackHawk May 29 '17 at 18:09
  • Because the threads are synchronous. t2 could finish _before_ t1 even though you run `t1.join()` first. The more control you want over the thread operation the less like a threaded program it is. You shouldn't worry about which thread runs first or finishes first. @blackHawk – Gray May 29 '17 at 20:44
0

Basically when you do those three lines

t1.start();
t2.start();
Log.i("MainActivity " , " thread counter" + THREAD_COUNTER);

they're all happening at the same time , so your thread counter doesn't update when the Log.i happens , you can use asynctask and print in the end of the thread, or do log.i in the thread itself ,

when you print like this you simply print before the threads updated the var.

For more on multithreading in java (for learning ):

http://beginnersbook.com/2013/03/multithreading-in-java/

for more on asynctask (android thread with a lifecycle so you can do things in the UI once it's over):

https://developer.android.com/reference/android/os/AsyncTask.html

yanivtwin
  • 617
  • 8
  • 32