How to sync two threads in different classes - java

I need to have two threads synchronized such that both cannot run concurrently. Once called, they need to run so if the other thread is running, they need to wait until the other one is done and then run after it. I know I can use join() but my question involves threads in different classes with no reference to each other. Is it a good idea to make the threads static class variables so they both can access each other?
One thread (t1) is called from a method in the Main Activity and the other thread (t2) is inside an AsyncTask:
public class MainActivity extends AppCompatActivity
{
public void someMethod()
{
// code
Thread t1 = new Thread(() ->
{
// run thread code
});
t.start();
try
{
t.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
// someMethod follow-up code
}
}
public class FetchData extends AsyncTask<Void, Void, Void>
{
protected final Void doInBackground(Void... params)
{
// code
Thread t2 = new Thread(() ->
{
// run thread code
});
t.start();
try
{
t.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
// follow-up code
}
}
}

I executed the synchronization by adding static class thread variables and added a sleep factor so I could test:
public class MainActivity extends AppCompatActivity implements Interface.InterfaceCommon
{
public static Thread t1;
FetchData fetchData;
#Override
protected void onCreate(Bundle savedInstanceState)
{
t1 = new Thread();
fetchData = new FetchData();
}
public void someMethod()
{
Runnable r = () ->
{
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
/// Some code
};
t1 = new Thread(r);
try
{
FetchData.t2.join();
t1.start();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
public class FetchData extends AsyncTask<Void, Void, Void>
{
public static Thread t2;
public FetchData()
{
t2 = new Thread();
}
protected final Void doInBackground(Void... params)
{
Runnable r = () ->
{
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
/// Some code
};
t2 = new Thread(r);
try
{
MainActivity.t1.join();
t2.start();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}

You can use two blocking queues, one for each thread. They would each start working when they read from their queue, and they stop by writing to the other thread's queue. That way, there's always one that's active. They could pass just a token, or an object with data.

Related

How to synchronize MesageReceivedEvent from main EventListener with a new variable inside Thread only when it is updated by main's listener

I need to create a new Thread that will execute a method when and only when the MessageReceivedEvent is updated inside the main ListenerAdapter, and let the thread sleep whenever the variable is not updated.
This thread should run independently from the main thread and not stop new requests.
This is the thread class,
private static final class Worker extends Thread {
private volatile boolean running = false;
MessageReceivedEvent event; //this must update along with the listener
private boolean validateData() {
if (//something) {
return true;
}
return false;
}
private void waitForInput() {
boolean hasInput = false;
try {
while (!hasInput) {
hasInput = validateData();
if (!hasInput) {
Thread.sleep(10);
}
}
} catch (InterruptedException iex) {
Thread.currentThread().interrupt();
}
}
#Override
public void run() {
running = true;
while (running) {
waitForInput();
//do something
}
}
}
It is an inner class ran by a request from the main thread,
the MessageReceivedEvent inside it must be updated only when the actual event from the listener changes, otherwise it should do nothing.
When testing, it will only execute based on the MessageEvent that triggered the thread, how can I make this thread receive the updates?
public class Listener extends ListenerAdapter {
public static MessageReceivedEvent msgEvnt;
#Override
public void onMessageReceived(MessageReceivedEvent msgEvnt) {
Listener.msgEvnt = msgEvnt;
}
This is all the listener does, update the variable whenever there is a new messageEvent.
You can use a Condition Variable to accomplish this.
final ReentrantLock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
private void waitForInput() {
lock.lock();
Listener.msgEvnt = null;
try {
while (Listener.msgEvnt == null)
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
#Override
public void onMessageReceived(MessageReceivedEvent event) {
lock.lock();
try {
Listener.msgEvnt = msgEvnt;
condition.signal();
} finally {
lock.unlock();
}
}
See ReentrantLock and Condition
You can use a BlockingQueue
final BlockingQueue queue = new ConcurrentBlockingQueue();
private MessageReceivedEvent waitForInput() throws InterruptedException {
return queue.take();
}
#Override
public void onMessageReceived(MessageReceivedEvent event) {
queue.put(event);
}
You can use a Callback, this is what I would recommend.
Consumer<? super MessageReceivedEvent> callback;
private void onInput(Consumer<? super MessageReceivedEvent> callback) {
this.callback = callback;
}
#Override
public void onMessageReceived(MessageReceivedEvent event) {
if (this.callback != null)
this.callback.accept(event);
this.callback = null;
}
Example use:
listener.waitForInput(event -> {
System.out.printf("%#s: %s\n", event.getAuthor(), event.getMessage().getContentDisplay());
});
This is already provided by JDA-Utilities

Java Thread notify not called

I am trying to use thread wait and notify function, but noticed that notify function not calling my method again. Sharing my code. Please let me know what I'm doing wrong.
public class MainActivity extends AppCompatActivity {
Thread t;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
t = new Thread(new Runnable() {
#Override
public void run() {
List<Parent> threadList = new ArrayList<>();
threadList.add(new Task1(MainActivity.this));
threadList.add(new Task2(MainActivity.this));
for (Parent task : threadList) {
try {
task.execute();
t.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();
}
public void getResult(int i) {
Log.i("###","Notified"+i);
t.notify();
}
}
class Task1 implements Parent{
public int total;
MainActivity mainActivity;
Task1 (MainActivity c) {
mainActivity = c;
}
#Override
public void execute() {
for(int i=0; i<200 ; i++){
total += i;
Log.i("###1", ""+i);
}
mainActivity.getResult(1);
}
}
Task 2 is not getting executed after Task1

Auto updating UI with a different thread

I have an Android App which constantly auto updating a list of data from the App's SQLite which an ArrayAdapter is used for handling the data, So for this I've made another thread or handler from the onCreate method of the Acitivity, and inside it's code there's a continuous loop for updating then waiting (or sleeping the thread for a moment, ex/ 10 sec), There are two problems involved:
1- Only the UI thread can touch it's views (though I only touched ArrayAdapter if it counts as a View).
2- Once the other thread starts to run, The UI thread seems to stuck in it, and won't update even the first UI update (complete white).
codes for the autoUpdate() method: (which is called on the last line of the UI onCreate method):
public void startAutoUpdateLogData(final int milliseconds){
continueAutoUpdate = true;
new Thread(){
#Override
public void run() {
while(continueAutoUpdate){
try{
Log.v("updating..", "");
updateLogFromDatabase();
Thread.sleep(milliseconds);
}catch(Exception e){
e.printStackTrace();
}
}
}
}.start();
}
OR:
public void startAutoUpdateLogData2(final int milliseconds){
continueAutoUpdate = true;
runOnUiThread(new Runnable() {
#Override
public void run() {
while(continueAutoUpdate){
try{
Log.e("updating...", "");
updateLogFromDatabase();
Thread.sleep(milliseconds);
}catch(Exception e){
e.printStackTrace();
}
}
}
});
}
OR
public void startAutoUpdateLogData3(final int milliseconds){
continueAutoUpdate = true;
final Handler handler = new Handler();
runOnUiThread(new Runnable() {
#Override
public void run() {
while(continueAutoUpdate){
try{
handler.postDelayed(new Runnable(){
public void run(){
Log.e("updating...", "");
updateLogFromDatabase();
}
}, milliseconds);
}catch(Exception e){
e.printStackTrace();
}
}
}
});
}
Neither of these work.
You can do many ways. But this one will be more closer solution to what you have done.
private void runThread() {
new Thread() {
public void run() {
while (continueAutoUpdate) {
try {
handler.postDelayed(new Runnable(){
public void run(){
Log.e("updating...", "");
updateLogFromDatabase();
}
}, milliseconds);
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
After trying various stuff, I finally found the solution: Anytime you have some long-run tasks to perform, you can assign a new Java thread to execute it, but when there's a need to update the UI from that thread, which can't be directly accessing any components of the UI, So in that case you only need to wrap the code with runOnUiThread() inside the other thread. ex/
private void startAutoUpdateLogData(final int milliseconds) {
final Handler handler = new Handler();
continueAutoUpdate = true;
new Thread() {
public void run() {
while (continueAutoUpdate) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("updating...", "");
updateLogFromDatabase();
}
});
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}

Android - asynctask don't show image when a use get(time)

I try to do app which show elements. Each element should start showing when the before element was hidden. Each element is showing 2 seconds. I try a lot of way:
Android/java - How to do that loop wait to do action
And now I try with Asynctask. I find a way:
public class MainActivity extends Activity
{
ImageView image1,image2;
int id = 0;
AsyncTask.Status status;
TextView txt;
String status1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LongOperation task = new LongOperation();
status = task.getStatus();
status1 = String.valueOf(status);
txt = (TextView) findViewById(R.id.txt);
image1 = (ImageView)findViewById(R.id.image1);
image2 = (ImageView)findViewById(R.id.image2);
do{
new LongOperation().execute("");
id=id+1;
txt.setText(status1);
try
{
try
{
task.get(2500, TimeUnit.MILLISECONDS);
} catch (TimeoutException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}while(id<3);
}
private class LongOperation extends AsyncTask<String, Void, String>
{
#Override
protected void onPreExecute()
{
image1.setVisibility(View.VISIBLE);
image2.setVisibility(View.VISIBLE);
txt.setText(status1);
}
#Override
protected String doInBackground(String... params) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.interrupted();
}
return null;
}
#Override
protected void onPostExecute(String result) {
txt.setText("Executed");
image1.setVisibility(View.GONE);
image2.setVisibility(View.GONE);
}
#Override
protected void onProgressUpdate(Void... values) {}
}
(This is a example). App run and end after 7.5 sec (everything ok) but images aren't shown when I start. What should I do?
I think you are creating a deadlock situation with your threads. The main UI thread is blocking at the line task.get(), which in turn is preventing the AsyncTask from running properly; its onPreExecute method is posted onto the UI Thread, and the doInBackground doesn't run until onPreExecute completes.

How to 'flush' UI Thread actions before continue execution

I've got a problem in Android with runOnUiThread. I start an AsyncTask (inside an Activity) that waits for a while, and after calls the method showDialog(id). After this call, it sleeps for another while, and finishes calling the method dismissDialog(id).
This is the code:
public class MyActivity extends Activity {
...
protected class StartWaiting extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Show dialog
runOnUiThread(new Runnable() {
#Override
public void run() {
showDialog(PROGRESS_DIALOG_LOADING);
}
});
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Dismiss dialog
runOnUiThread(new Runnable() {
#Override
public void run() {
dismissDialog(PROGRESS_DIALOG_LOADING);
}
});
return null;
}
#Override
protected void onPostExecute(Void arg) {
new StartServices().execute();
}
}
}
Unfortunately, the behaviour is different from what I want to do: showDialog() and dismissDialog() are called one immediately after the other.
I think that the reason why this happens is that the UI Thread execute both actions "when it can", that is at the end of sleeping actions.
Well, does it exist some "flushUI()" method that force a thread (in this case, the UI Thread) to execute every action before continue?
You could just add a synchronization point in your thread, using a CountDownLatch for instance:
final CountDownLatch latch = new CountDownLatch(1);
view.post(new Runnable() {
public void run() {
try {
// Do stuff on the UI thread
} finally {
latch.countDown();
}
}
});
try {
if (!latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS)) {
return;
}
} catch (InterruptedException e) {
// Handle exception
}

Categories

Resources