How do I prevent threads from interfering with each other in Java?

In summary: SetQuestion and ButtonChooser in separate threads. This isn't how threading works in Java. In summary, the problem is that the questions and answers stop matching when multiple threads are running.
  • #1
Darkmisc
204
27
TL;DR Summary
I have a runnable that works fine when it's the only thread that I run. However, the timing of its steps suffers when I run multiple threads on handler.
Hi everyone

I'm making a Whack-a-mole-style game for learning katakana. I have a textView for the question, a textView for the answer and nine buttons.

I have a SetQuestion runnable to show the question and answer. Each button has its own runnable that controls how long the button flashes, what text it displays and how many button presses are required. Another runnable called "Button Chooser" determines which buttons flash.

The SetQuestion runnable works fine when it is the only thread in handler. However, the questions and answers stop matching when I run SetQuestion with Button Chooser.

I've tried running SetQuestion and Button Chooser and separate handlers and it doesn't fix the problem.

This is the code for SetQuestion

public Runnable SetQuestion = new Runnable() {


SetQuestion:
public Runnable SetQuestion = new Runnable() {

        public void run() {
            Qtimer++;
            if (Qtimer%10==1){
                pickFromArray = ThreadLocalRandom.current().nextInt(0, arraySize);
//                whichSound();
                textView29.setText(listromT.get(pickFromArray));
                hintView.setText(listT.get(pickFromArray));
            }
            if (Qtimer%10==6){
//                whichSound();
                pickFromArray2 = ThreadLocalRandom.current().nextInt(0, arraySize);
                textView29.setText(listromT.get(pickFromArray));
                hintView.setText(listT.get(pickFromArray));
            }
            if (Qtimer>199){
                Qtimer=110;
            }
            handler2.postDelayed(this, 1000);
        }
    };

textView29 has the question and hintView the answer. It seems running multiple threads is causing enough lag so that the questions and answers get out of synch. Is there a way to fix this?Thanks
 
Technology news on Phys.org
  • #2
Here's a brief tutorial on developing safe thread code in java using the synchronized keyword on methods and in rare cases the Lock class to insure only one thread is executing the given code blocks.

https://www.javacodegeeks.com/2015/09/concurrency-best-practices.html

A lot of other things are covered like use of collection classes designed for multi-threaded use.
 
  • Like
  • Informative
Likes berkeman, Wrichik Basu and Darkmisc
  • #3
I've tried fixing the problem by assigning priority to SetQuestion and by running ButtonChooser on a background thread. The textViews for the question and answer still change out of synch. Does anyone have any ideas on how to fix it?

This is the code I used for assigning priority to SetQuestion. (The OP ran SetQuestion on handler2, but now it's on handler.)

assign priority:
        HandlerThread handlerThread = new HandlerThread("SetQuestion");
        handlerThread.start();
        Looper looper = handlerThread.getLooper();
        Handler handler = new Handler(looper);
        handlerThread.setPriority(Thread.MAX_PRIORITY);

        handler.post(SetQuestion);

        HandlerThread handlerThread2 = new HandlerThread("ButtonChooser");
        handlerThread2.start();
        Looper looper2 = handlerThread.getLooper();
        Handler handler2 = new Handler(looper2);
        handlerThread2.setPriority(Thread.MIN_PRIORITY);

        handler2.post(ButtonChooser);

This is the code I used to run ButtonChooser on a background thread:
background thread:
        HandlerThread handlerThread = new HandlerThread("SetQuestion");
        handlerThread.start();
        Looper looper = handlerThread.getLooper();
        Handler handler = new Handler(looper);
        handlerThread.setPriority(Thread.MAX_PRIORITY);

        handler.post(SetQuestion);

        ExecutorService executor = Executors.newCachedThreadPool();
        executor.submit(ButtonChooser);
Have I used incorrect code? Or did I have the wrong idea with assigning priority and running ButtonChooser on a background thread?
 
Last edited:
  • #4
It sounds like you are trying to sequence threads by setting priorities. Bad idea. It's not even guaranteed to do what you want.

You should sequence them directly, using blocking, semaphores, etc.
 
Last edited:
  • Like
Likes harborsparrow and Darkmisc
  • #5
Yes, synchronize them directly. But if you want them to work in a certain order, why even use threads?
 
  • Like
Likes Darkmisc
  • #6
I wanted the buttons to flash randomly, but I didn't realise that using threads would interfere with my SetQuestion runnable.

I've tried to fix the problem by using the synchronized command:

synchronized:
    public void QandA(){
        synchronized (this){
        pickFromArray = ThreadLocalRandom.current().nextInt(0, arraySize);
        textView29.setText(listromT.get(pickFromArray));
        hintView.setText(listT.get(pickFromArray));}
    }

I thought it would force the CPU to read the three commands in the brackets as a single block, but it didn't work. TextView29 and hintView still change out of sync. Is there a command that will ensure pickFromArray, textView29.setText and hintView.setText will always be processed together without other commands from other threads coming in between?

The buttons don't have this problem. That is, the colour change and text change for them always happen in-synch. I'm not sure why it's only happening with the textViews.
 
  • #7
The whole point of using threads is for things to "seem" to happen in parallel. I've only ever used threads when something long-running needed to happen and I didn't want that long-running thing to block the user interface--so that, for example, I could cancel the long-running thing if I wanted to.

I don't understand exactly what you are doing, but if you have threads running in the background at the same time you are trying to do these actions, you do NOT have control over the order in which things may be done.
I've used threads mainly for file copying--scraping files from the web, maybe, or just copying a large batch of files from one place to another. Those operations take a while. In the case of the scraper, to make it get done faster, I would launch about 3 background threads and let them work on downloading files, and my user interface would not be frozen in the meantime.

THINGS HAPPENING IN PARALLEL is when you need more than one thread.
Also, you need a way to coordinate threads with the main thread, so that the background threads can notify the main thread of progress, or the main thread can tell the background thread to stop. This is an advanced programming topic, and different languages and companies and OS's use completely different vocabularies to talk about it. So, are you working on Linux or Windows?

In Java, you'll need to understand the Publish-Subscribe "design pattern" and also understand delegates which can be used for cross-thread communications. When an event handler "fires", i.e., executes, all these things are being used. If you don't understand the theory, then you need to stop trying to write a real program and write a test learning program. Start by creating a bogus long-running job of some sort--maybe it counts to 1000 but only at one-second intervals. Try creating one thread to do that and make a way for your main thread to be notified of progress (and show that to the user) or to cancel the thread. If you can make that work, you'll understand threading.
 
  • Like
Likes Darkmisc and Jarvis323
  • #8
harborsparrow said:
The whole point of using threads is
I'm not sure I agree.

I've used them for load balancing. Say I have an 8C8T processor. If I divide the work into 8 pieces, one the first piece finishes, that core is idle. I can try to make them all take the same amount of time, but that doesn't mean I'm very good at it.

If I instead divide it into 1000 pieces, as soon as one piece finishes, I can start another one. Threads can be a natural way to do this - create 1000 threads, block 992 of them, and as each thread terminates, it unblocks a new one.

Years ago, I wrote a communications program that was trivial to use threads. One thread read the keyboard, and if there was activity, put it in Buffer A. Another thread read buffer A and if it wasn't empty, sent it to the modem. A third thread read the modem and if there was activity, put it in Buffer B. The fourth thread looked at Buffer B, and if there was activity, put it on the screen.

Was this the only way? Of course not. It was, however, simple to write and simpler to debug than a monolithic block of code.
 
  • #9
Vanadium 50 said:
I've used them (threads) for load balancing. Say I have an 8C8T processor. If I divide the work into 8 pieces, one the first piece finishes, that core is idle. I can try to make them all take the same amount of time, but that doesn't mean I'm very good at it.

That's interesting. In today's world, it may also be unnecessary, as processors with multiple cores are extremely clever at doling out the work to be done across the cores at the hardware level. They use fancy storyboards to keep it all true semantically to sequential processing, but believe me, the processor is always using every single core if at all possible. There is no need at all for a programmer to jump through hoops in most cases. But back in the day, when hardware was not yet smarter than a firecracker, maybe it saved time to do so.
 
  • #10
Vanadium 50 said:
Years ago, I wrote a communications program that was trivial to use threads. One thread read the keyboard, and if there was activity, put it in Buffer A. Another thread read buffer A and if it wasn't empty, sent it to the modem. A third thread read the modem and if there was activity, put it in Buffer B. The fourth thread looked at Buffer B, and if there was activity, put it on the screen.

Was this the only way? Of course not. It was, however, simple to write and simpler to debug than a monolithic block of code.

But if none of the threads are doing significantly heavy tasks, then at best you're making it possible for some updates to happen unnecessarily fast (in terms of performance). It usually does't matter if your keyboard buffer is updated 1 million times faster than your screen's refresh rate. And if your threads are constantly spinning needlessly, then you're also consuming extra energy and interfering with the efficiency of your operating system and other programs running on your machine. Usually, even if you use one thread only for repeating lightweight tasks, you want to insert sleep commands to give the core a break and let it be free to do something else between repetition.

Simplicity of debugging is not often considered a pro of using multiple threads either, but I can't judge in your case.

In my opinion, just because you have multiple separate continuously executing tasks, it isn't necessarily a good idea to always have them execute on separate threads.
 
  • #11
harborsparrow said:
That's interesting. In today's world, it may also be unnecessary, as processors with multiple cores are extremely clever at doling out the work to be done across the cores at the hardware level. They use fancy storyboards to keep it all true semantically to sequential processing, but believe me, the processor is always using every single core if at all possible. There is no need at all for a programmer to jump through hoops in most cases. But back in the day, when hardware was not yet smarter than a firecracker, maybe it saved time to do so.

I can verify that running a data parallel task over multiple blocks of the data on multiple separate threads does result in a speed up proportional to the number of threads.

And at the OS or hardware level, it can't just take what is coded as a sequential task and automatically split it into multiple parallel threads because it could result in race conditions.

If your thread level parallelism isn't balanced, then it will result in loss of performance because you won't be feeding separate threads of instructions to all cores continuously.

At the process level, there are no race conditions, (unless introduced through network or file system based communication), so the other processes can still use up the free cycles on the free cores. But your computer doesn't usually have enough background tasks that it needs what you'd be leaving free by not load balancing.
 
Last edited:
  • #12
harborsparrow said:
In today's world, it may also be unnecessary, as processors with multiple cores are extremely clever at doling out the work to be done across the cores
It was in a modern processor. I had 13 tasks on a 12C24T processor. There was about a factor of 3 between the slowest and the fastest. I converted it to 325 threads and let the scheduler do this for me.

And yes, there were other ways I could have written this. But this let me efficiently keep the processor busy.
 
  • #13
I'm using Windows.

I didn't know using multiple threads would mess up my plans. I've switched everything over to methods now, except one runnable that runs recursively.

setQ:
public Runnable SetQuestion = new Runnable() {

        public void run() {

            runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    Qtimer++;
                    if (Qtimer%10==1){
                        ChooseButton();
                    }
                    if (Qtimer%10==2){
                        ChooseButton();

                    }
                    if (Qtimer%10==3){
                        ChooseButton();
                    }

                     if (Qtimer%10==6){
                        Qtimer=110;
                    }
                    handler2.postDelayed(this, 1000);
                }
            });

        }
    };
This is the method for choosing buttons:

buttonchooser:
public void ChooseButton(){

    int which = ThreadLocalRandom.current().nextInt(1, 10);

    if (which ==1){

        if(!isFlashing1.get()) Button1();

    }

    if (which ==2){

        if(!isFlashing2.get()){

            Button2();

        }

    }

    if (which ==3){

        if(!isFlashing3.get())Button3();

    }

    if (which ==4){

        if(!isFlashing4.get()) Button4();

    }

    if (which ==5){

        if(!isFlashing5.get())Button5();

    }

    if (which ==6){

        if(!isFlashing6.get())Button6();

    }

    if (which ==7){

        if(!isFlashing7.get())Button7();

    }

    if (which ==8){

        if(!isFlashing8.get())Button8();

    }

    if (which ==9){

        if(!isFlashing9.get())Button9();

    }
}

This is the method that controls each button:

button:
public void Button9(){
    try {

         TimeUnit.MILLISECONDS.sleep(ThreadLocalRandom.current().nextInt(300, 600));

    } catch (InterruptedException e) {

        e.printStackTrace();

    }
    Collections.shuffle(listF);

    int textCoin = ThreadLocalRandom.current().nextInt(1, 3);

    if (textCoin == 1) {

        button9.setText(hintView.getText().toString());

    } else {

        Collections.shuffle(listF);

        int whereIsAns = listF.indexOf(hintView.getText().toString());

        if (whereIsAns == 0) {

            button9.setText(listF.get(1));
        }

        if (whereIsAns == listF.size() - 1) {

            button9.setText(listF.get(1));

        } else {

            button9.setText(listF.get(whereIsAns + 1));

        }

    }
    int colour = ThreadLocalRandom.current().nextInt(1, 3);
    if (colour == 1) {

        button9.setBackgroundColor(Color.rgb(78, 162, 245));

        req9 = 1;

        isFlashing9.set(true);

    } else {

        button9.setBackgroundColor(Color.rgb(56, 98, 173));

        req9 = 2;

        isFlashing9.set(true);

    }
    try {

         TimeUnit.MILLISECONDS.sleep(2000);

    } catch (InterruptedException e) {

        e.printStackTrace();

    }

    button9.setBackgroundColor(Color.rgb(0, 0, 0));

    button9.setText(" ");

    isFlashing9.set(false);

    timerInt9 = 110;

    clicked9 = 0;

}

I think TimeUnit.MILLISECONDS.sleep(2000) has messed everything up. The textViews and buttons no longer update (same thing happens with Thread.Sleep()).

I've also tried getting the buttons to turn off by referencing SystemClock.uptimeMillis() + 2000, but that doesn't work either.

Are there other ways to make the button flash for two seconds and then turn off?

I got it working before with TimerTasks, runnables and executor service, but all of these gave me problems with mismatching textViews.
 
  • #14
Does anyone know what's gone wrong with this idea?

I've tried using runnables for the buttons and ButtonChooser again because they are the most convenient way I know to make the buttons turn off after two seconds. I figured if the problem was thread interference, I might solve it by clearing all threads from handler2 before calling the SetQuestion runnable.

setQ:
public Runnable SetQuestion = new Runnable() {
       public void run() {
           runOnUiThread(new Runnable() {
               @Override

               public void run() {

                   Qtimer++;

                   if (Qtimer%10==1){

                       handler2.removeCallbacksAndMessages(null);

                       QandA();

                   }

                   if (Qtimer%10==2){

                       handler2.post(ButtonChooser);                    }
             
                   if (Qtimer%10==4){
                       handler2.removeCallbacksAndMessages(null);
                   }
                   if (Qtimer%10==6){
                       Qtimer=110;
                   }
                   handler2.postDelayed(this, 1000);
               }
           });
       }

   };
I'm still getting the same result (textViews don't update in-sync). Is it because I can't control when handler2.removeCallbacksAndMessages(null) will be run? NB: Everything runs on handler2. There are no other handlers.
 
  • #15
Darkmisc said:
Are there other ways to make the button flash for two seconds and then turn off?
Yes, use a game loop.
 
  • Like
Likes Darkmisc
  • #16
Look up apartment threading. I might be out of date, but java has a single UI thread. So updates need to be queued to it.
 
  • Like
Likes Darkmisc

1. How do I create and manage threads in Java?

In order to create threads in Java, you can either extend the Thread class or implement the Runnable interface. Once you have created a thread, you can use methods such as start(), join(), and sleep() to manage and control its execution.

2. How do I ensure thread safety in Java?

Thread safety in Java can be achieved by using synchronization. This can be done by using the synchronized keyword or by using the synchronized block. This ensures that only one thread can access a particular code block at a time, preventing interference from other threads.

3. What is a deadlock in Java?

A deadlock in Java occurs when two or more threads are waiting for each other to release a resource, resulting in a circular waiting state. This can lead to a situation where none of the threads can proceed, causing the program to hang.

4. How can I avoid deadlocks in Java?

To avoid deadlocks in Java, it is important to ensure that threads always acquire resources in the same order. This means that if one thread acquires resource A before resource B, then all other threads should also acquire resource A before acquiring resource B. Additionally, you can use the join() method to specify a maximum time for a thread to wait for a resource to become available.

5. What are the best practices for thread management in Java?

Some best practices for thread management in Java include using thread pools instead of creating threads for each task, minimizing the use of global variables, and properly handling exceptions in threads. It is also important to avoid unnecessary synchronization and to properly terminate threads when they are no longer needed.

Similar threads

  • Programming and Computer Science
Replies
4
Views
2K
Back
Top