I am trying to print a synchronized Integer object (mInt) using two threads till 10. However either one of the thread locks the other thread throws the exception pasted below. Can someone point my mistake here. This is more of a Java related question however included "android" tag because I have coded it for android and I need to tryout sometime in it.
09-24 15:24:17.198 10621-11400/com.sameer.android.samplecode
E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-364
Process: com.sameer.android.samplecode, PID: 10621
java.lang.IllegalMonitorStateException: object not locked by thread before notify()
at java.lang.Object.notify(Native Method)
at com.sameer.android.samplecode.MainActivity$Even.run(MainActivity.java:55)
public class MainActivity extends AppCompatActivity {
private Integer mInt;
class Odd extends Thread {
private final String TAG = Odd.class.getSimpleName();
#Override
public void run() {
Log.i(TAG, "Odd() Started....");
synchronized (mInt) {
try {
while (mInt <= 10)
{
while (mInt % 2 != 1) {
Log.i(TAG, "Odd... Looping " + mInt);
mInt.wait();
}
mInt++;
Log.i(TAG, "Odd " + mInt);
mInt.notify();
}
}
catch (InterruptedException e) {
Log.e(TAG, "Odd() " + e.getMessage());
}
}
Log.i(TAG, "Odd() Ended....");
}
}
class Even extends Thread {
private final String TAG = Even.class.getSimpleName();
#Override
public void run() {
Log.i(TAG, "Even() Started....");
synchronized (mInt) {
try {
while (mInt <= 10)
{
while (mInt % 2 != 0) {
Log.i(TAG, "Even... Looping " + mInt);
mInt.wait();
}
mInt++;
Log.i(TAG, "Even " + mInt);
mInt.notify();
}
}
catch (InterruptedException e) {
Log.e(TAG, "Even() " + e.getMessage());
}
}
Log.i(TAG, "Even() Ended....");
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInt = new Integer(0);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Even even = new Even();
even.start();
Odd odd = new Odd();
odd.start();
}
});
}
}
When you increment mInt, you do not modify the current Integer object but create a new Integer object. Thus, the call to notify is performed on the new (unlocked) object. As notify must be called on the object that is locked, the IllegalMonitorStateException occurs.
Additional Side Remark (not part of answer):
Your code has a fundamental problem. You lock mInt at the beginning of both run methods. Thus, only one of your thread can enter its synchronized block. The second thread, will wait for the lock on mInt until the first thread leaves it synchronized block, ie, terminates. Thus, you end up in a deadlock because the first thread increments only a single time and waits inside its synchronized block for the other thread to do the next increment. However, the second thread cannot perform this operation as it cannot enter its own synchronized block (until the first thread releases the lock on mInt).
Thanks Matthias! Your response (partially) helped me solved the issue which I was suspecting and you nailed it. The issue was with mInt getting newly created and hence losing reference. I fixed the issue by creating a class similar to Integer. I have pasted the code below.
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Value mInt;
class Odd extends Thread {
private final String TAG = Odd.class.getSimpleName();
#Override
public void run() {
Log.i(TAG, "Odd() Started....");
synchronized (mInt) {
try {
while (mInt.get() < 10)
{
while (mInt.get() % 2 != 1) {
mInt.wait();
}
Log.i(TAG, "Odd " + mInt.get());
mInt.inc();
mInt.notify();
}
}
catch (InterruptedException e) {
Log.e(TAG, "Odd() " + e.getMessage());
}
}
Log.i(TAG, "Odd() Ended....");
}
}
class Even extends Thread {
private final String TAG = Even.class.getSimpleName();
#Override
public void run() {
Log.i(TAG, "Even() Started....");
synchronized (mInt) {
try {
while (mInt.get() < 10)
{
while (mInt.get() % 2 != 0) {
mInt.wait();
}
Log.i(TAG, "Even " + mInt.get());
mInt.inc();
mInt.notify();
}
}
catch (InterruptedException e) {
Log.e(TAG, "Even() " + e.getMessage());
}
}
Log.i(TAG, "Even() Ended....");
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInt = new Value();
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mInt.set();
Even even = new Even();
even.start();
Odd odd = new Odd();
odd.start();
}
});
}
}
class Value {
private int member;
public Value() {
member = 0;
}
public int get() {
return member;
}
public void inc() {
this.member++;
}
public void set() {
this.member = 0;
}
public void dec() {
this.member--;
}
}
Related
I have two threads in my main activity from Runner and start them with clicking a button. The only thing thy do is count up. I want to update two TextViews wit the current count from ech thread. When i start my app and click my button, the app crashed.
The code run perfektly in the console.
The class Runner is only used for the counting. I want to Update the two TextViews after each passage in the methode running().
public class Runner extends Activity implements Runnable {
int count = 0;
String name;
public Runner(String name) {
super();
this.name = name;
}
public void warten() throws InterruptedException {
int zahl = (int) (Math.random() * 500) + 500;
Thread.sleep(zahl);
}
public void running() throws InterruptedException {
for(int i = 0; i < 10; i++) {
warten();
count++;
System.out.println(name + " ist bei: " + count);
if(count == 10) {
System.out.println(name + " IST FERTIG");
}
runOnUiThread(new UiThread(name, count));
}
}
public void run() {
try {
running();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The class UiThread should be the main thread for updating the UI.
public class UiThread extends Activity implements Runnable {
String name;
int count;
TextView textView1;
TextView textView2;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView1 = findViewById(R.id.textView2);
textView2 = findViewById(R.id.textView3);
}
public UiThread(String name, int count){
this.name = name;
this.count = count;
}
#Override
public void run() {
if(name == "thread1"){
textView1.setText("thread1 ist bei: " + count);
}else{
textView2.setText("thread2 ist bei: " + count);
}
}
}
i would recommend you checkout this guide on android threading docs.
You can't initialize an activity class, you only add it to the manifest, doing so will lead to a null context. So remove the constructor in your UiThread class.
Also you do not need for your runner class to extend Activity. Pass an instance of Activity inorder to use the runOnUiThread() method.
Here is an example of how the UiTHread class should be.
public class UiThread extends Activity {
public TextView textView1;
public TextView textView2;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView1 = findViewById(R.id.textView2);
textView2 = findViewById(R.id.textView3);
startThreads();
}
private void startThreads(){
// Initialize the runnable class passing this activity context.
Runner runner = new Runner(this);
Thread thread1 = new Thread(runner, "thread1");
Thread thread2 = new Thread(runner, "thread2");
thread1.start();
thread2.start();
}
}
the runner class
public class Runner implements Runnable {
private int count = 0;
private UiThread context;
public Runner(UiThread activityContext) {
this.context = activityContext;
}
public void warten() throws InterruptedException {
int zahl = (int) (Math.random() * 500) + 500;
Thread.sleep(zahl);
}
public void running() throws InterruptedException {
for(int i = 0; i < 10; i++) {
warten();
count++;
System.out.println(Thread.currentThread().getName() + " ist bei: " + count);
if(count == 10) {
System.out.println(Thread.currentThread().getName() + " IST FERTIG");
}
// update text views from the main thread.
context.runOnUiThread(new Runnable() {
#Override
public void run() {
if(Thread.currentThread().getName().equals("thread1")){
context.textView1.setText("thread1 ist bei: " + count);
}else{
context.textView2.setText("thread2 ist bei: " + count);
}
}
});
}
}
public void run() {
try {
running();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Hope this helps.
I have two handlers. Handler in a handler. Both of them are in a for-loop.
The overview is something like this,
for{
handler.postDelayed(runnableA{
for{
handler2.postDelayed(runnableB{
function();
}, 3000);
}
}, 1000);
}
I wanted to end handlers' work at any time when the user clicks back button. So, I created two Runnable Classes so that I can use something like runnableA.removellbacksAndMessages(null).
Handler messageHandler;
Handler countDownHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, "Start Play in 5 seconds", Toast.LENGTH_SHORT).show();
countDownHandler = new Handler();
for (int i = 7; i >= 0; --i) {
final int idx = i;
Runnable countRunnable = new CountRunnable(idx, countDownView);
countDownHandler.postDelayed(countRunnable, 1000 * (7 - i));
}
}
And this is Runnable Classes.
public class CountRunnable implements Runnable {
int idx;
TextView countDownView;
public CountRunnable(int idx, TextView countDownView) {
this.idx = idx;
this.countDownView = countDownView;
}
#Override
public void run() {
int messageSize = messageItems.size();
for (int j = 0; j < messageSize; j++) {
final int jdx = j;
messageHandler = new Handler();
Runnable messageRunnable = new MessageRunnable(jdx);
messageHandler.postDelayed(messageRunnable, 3000 * jdx);
}
}
}
class MessageRunnable implements Runnable {
int jdx;
public MessageRunnable(int jdx) {
this.jdx = jdx;
}
#Override
public void run() {
addMessageView(messageItems.get(jdx));
}
}
This is onBackPressed():
#Override
public void onBackPressed() {
super.onBackPressed();
Toast.makeText(getApplicationContext(), "All Work Ended.", Toast.LENGTH_SHORT).show();
scrollFlag = true;
try {
messageHandler.removeCallbacksAndMessages(null);
} catch (Exception e) {
Log.d(TAG, "messageHandler never used");
e.printStackTrace();
}
try {
countDownHandler.removeCallbacksAndMessages(null);
} catch (Exception e) {
e.printStackTrace();
}
}
public void addMessageView(String message){
try{
mTextView.setText(message);
}catch(Exception e){
Toast.makeText(getApplicationContext(), "Abnormal End", Toast.LENGTH_SHORT).show();
}
}
But, I keep getting errors because the activity already ended but the handlers can't find the activity. So, Abnormal End Toast message shows as many as the size of inner for loop.
I can ignore this if I don't use the Toast message, but I am afraid of Memory leak or Bad formed Program or something like that.
How can I fix this problem?
The main problem is that you are creating n numbers of CountRunnables and m number MessageRunnables. Despite creating more than one numbers of handlers you are removing callbacks only for the latest-created Hanlder.
Here's what you should do:
Keep a reference of all the Handlers and Runnables and call messageHandler.removeCallbacksAndMessages(null); and countDownHandler.removeCallbacksAndMessages(null); on all of them.
I'd like to get the string value output from AsyncTask. And store it into a variable on my main thread. How can I do so?
I tried to do store = new ReceiveData().execute().get() however it throws an execution exception error. But anyway, my question is not about the execution exception error. I just need a way to get the string out, please help!
Here is my activity code:
public class MainActivity extends AppCompatActivity { //MAIN ACTIVITIES (REMOTE)
double multiplier;
int seekbarvalue, finallumens;
#Override
protected void onCreate(Bundle savedInstanceState) {
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); //On orientation change socket will disconnect...
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Toast.makeText(MainActivity.this, LoginActivity.SERVER_IP, Toast.LENGTH_LONG).show();
//================START AFTER DEFAULT ON CREATE=================
SeekBar seekbarbrightness = (SeekBar) findViewById(R.id.seekbarbrightness);
final TextView tblumens, tbvolts, tbamps;
tblumens = (TextView) findViewById(R.id.tblumens);
seekbarvalue = seekbarbrightness.getProgress();
multiplier = (double) seekbarvalue / 100;
finallumens = (int) (multiplier * LoginActivity.enterlumens);
tblumens.setText(String.valueOf(finallumens) + " Lumens");
tbvolts = (TextView) findViewById(R.id.tbvolts);
tbamps = (TextView) findViewById(R.id.tbamps);
seekbarbrightness.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekbarbrightness, int progress, boolean b) {
if (b == true) {
seekbarvalue = seekbarbrightness.getProgress();
multiplier = (double) seekbarvalue / 100;
finallumens = (int) (multiplier * LoginActivity.enterlumens);
tblumens.setText(String.valueOf(finallumens) + " Lumens");
if (LoginActivity.getSocket() != null) {
try {
LoginActivity.getSocket().getOutputStream().write(String.valueOf(multiplier).getBytes());
new ReceiveData().execute();
//infinite loop here to keep receiving volts and amperes.
//Do a split and assign value to volt and amp
//String[] strrecv= store.split("|");
//String volts = strrecv[0];
//String amps = strrecv[1];
//tbvolts.setText("Voltage: " + volts + " V");
//tbamps.setText("Amperes:" + amps + " A");
} catch (IOException e) {
e.printStackTrace();
}
} else {
Toast.makeText(MainActivity.this, "NOT connected To Socket, please disconnect and reconnect!", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
And in my Asynctask I am doing this.
class ReceiveData extends AsyncTask<Void, Void, String> {
String str;
protected String doInBackground(Void... args) {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(LoginActivity.getSocket().getInputStream()));
str = in.readLine();
return str;
} catch (IOException e) {
e.printStackTrace();
String str = "fail";
return str;
}
}
protected void onPostExecute(String str) {
//super.onPostExecute(str);
}
}
The purpose of AsyncTask is to perform asynchronous task in a separate thread to free the main thread and avoid UX issues. For your purpose, I suggest transferring all of the work inside your try block inside the AsyncTask and update the UI after execution.
Something like this
In MainThread
new ReceiveData().execute();
In AsyncTask
class ReceiveData extends AsyncTask<Void, Void, Boolean> {
String volts;
String amps;
protected Boolean doInBackground(Void... args) {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(LoginActivity.getSocket().getInputStream()));
str = in.readLine();
String[] strrecv= store.split("|");
volts = strrecv[0];
amps = strrecv[1];
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
protected void onPostExecute(Boolean result) {
if (result) {
tbvolts.setText("Voltage: " + volts + " V");
tbamps.setText("Amperes:" + amps + " A");
}
}
}
Note that this only works if your AsyncTask is defined inside your Activity. If not, you need to create an interface from the AsyncTask and implement it in your activity and activate it onPostExecute
I have two threads.One is for incrementing the value.For each increment i neet to be notified the main thread.
Below is my main Thread which is a activity
public class MainActivity extends Activity {
private ProgressBar progressBar;
private int progressStatus = 1;
private TextView textView;
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
textView = (TextView) findViewById(R.id.textView1);
ProgressUpdate b = new ProgressUpdate();
b.start();
Log.e("SAMEERA", "Satrting ProgressUpdate");
synchronized (b) {
try {
Log.e("SAMEERA", "synchronized synchronized");
Log.e("SAMEERA", "progressStatus is "+b.total);
b.wait();
Log.e("SAMEERA", "progressStatus is "+b.total);
progressBar.setProgress(progressStatus);
textView.setText(progressStatus + "/" + progressBar.getMax());
} catch (InterruptedException e) {
}
System.out.println("Total is: " + b.total);
}
}
}
Below is my increment thread.
package com.example.zwtouch;
import android.util.Log;
public class ProgressUpdate extends Thread {
int total;
public void run() {
total=0;
synchronized (this) {
for (int i = 0; i < 100; i++) {
total += i;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e("SAMEERA", "run run total is "+i);
notify();
}
}
}
}
I need to notified each time if total is increased.But its not happening.After the for loop is finished it calls the main thread..where is the error ?
Option 1
Use Handler
Populate ProgressUpdate with ProgressBar and Handler objects.
On each progress use the Handler to update the ProgressBar
like this:
public class ProgressUpdate extends Thread {
int total;
ProgressBar mProgressBar;
Handler mHandler;
public ProgressUpdate(Handler h, ProgressBar pb) {
mHandler = h;
mProgressBar = pb;
}
public void run() {
total=0;
for (int i = 0; i < 100; i++) {
// Update the progress bar via a Handler
mHandler.post(new Runnable() {
public void run() {
mProgressBar.setProgress(i);
}
});
}
}
}
setup like this
new ProgressUpdate(handler, progressBar).start();
Option 2 (recommended)
This is another approach, You could use AsyncTask to achieve this aim. The advantage of this way is that both onProgressUpdate and onPostExecute runs on UI-Thread.
Make this class internal of MainActivity
private class ProgressUpdate extends AsyncTask<Void, Integer, Integer> {
protected Integer doInBackground(Void... dummy) {
int total = 0;
for (int i = 0; i < 100; i++) {
total += i;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e("SAMEERA", "run run total is "+i);
// Notify UI Thread
publishProgress(i);
}
return total;
}
protected void onProgressUpdate(Integer... i) {
// do something with 'i' on UI Thread
progressBar.setProgress(i);
}
protected void onPostExecute(Integer total) {
// do something with 'total' on UI Thread
// for instance
progressBar.setVisibility(View.GONE);
}
}
Setup ProgressUpdate on onCreate like this
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
new ProgressUpdate().execute();
// ...
}
Eclipse is offering final but I can't increase the i variable.
#Override
public void onClick(View v) {
final TextView tv = (TextView) findViewById(R.id.tvSayac);
int i = 1;
do {
try {
new Thread(new Runnable() {
public void run() {
tv.post(new Runnable() {
public void run() {
tv.setText(Integer.toString(i));
}
});
}
});
i++;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (i < 16);
}
A final is an entity that can not be changed after it is initialized.
Final (Java)
What you could do is create a variable within the scope of the do/while loop that is final with the value of i and send that into the function.
The easiest solution here is to create a class:
public class FinalCounter {
private int val;
public FinalCounter(int intialVal) {
val=intialVal;
}
public void increment(){
val++;
}
public void decrement(){
val--;
}
public int getVal(){
return val;
}
public static void main(String[] arg){
final FinalCounter test = new FinalCounter(0);
test.increment(); // 1
test.increment(); // 2
test.increment(); // 3
test.increment(); // 4
test.increment(); // 5
test.decrement(); // 4
System.out.println(test.getVal()); // prints 4
}
}
I think it is possible to create a local copy of the variable i. Try this:
#Override
public void onClick(View v) {
final TextView tv = (TextView) findViewById(R.id.tvSayac);
int i = 1;
do {
final int localCopy = i; // Create here a final copy of i
try {
new Thread(new Runnable() {
public void run() {
tv.post(new Runnable() {
public void run() {
// use here the copy
tv.setText(Integer.toString(localCopy));
}
});
}
}).start(); // Don't forget to start the Thread!
i++;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (i < 16);
}
By creating a final local copy:
the compiler won't complain anymore
because of Java copies by value, you will only increase i and not localCopy.
I suppose you want to start the Thread as well...
EDIT: Indeed, you were right. You have to create the local final copy inside the loop. Check the new code.
A final variable can only be initialized once not necessarily when you are defining it. It can be set any time within the constructor , but only once. In your case when you are incrementing i using i++, you are trying to assign the incremented value to i again which is not allowed.
You could create a counter class like that and increment it. This way, the reference of the Counter object could be final but you could still set its value ?
What I did was add a:
private int i;
Before this:
#Override
public void onClick(View v) {
final TextView tv = (TextView) findViewById(R.id.tvSayac);
i = 1;
do {
try {
new Thread(new Runnable() {
public void run() {
tv.post(new Runnable() {
public void run() {
tv.setText(Integer.toString(i));
}
});
}
});
i++;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (i < 16);
}
And you'll be able to use your variable as usual after that, without having to mark it as final.