I'm trying to run a thread until a mouse event occurs, which will trigger an interrupt to the thread. The problem is that I can't get the thread to stop running in an asynchronous way (i.e. to listen is a mouse event occurred). Instead, what happens is that the thread never exits the while loop. This is what I have so far:

private class aListener extends MouseAdapter {
   public void mousePressed(MouseEvent e) {
      if(condition){
         aThread.run();
      }
      else{
         aThread.interrupt();
      }
   }
}

...

private class workThread extends Thread {
   private volatile Thread blinker;
		
   public void run() {
      blinker = new Thread();
      blinker.run();
      Thread thisThread = Thread.currentThread();
      System.out.print(Thread.currentThread());

      while (true){
         try {
            doSomething();
            Thread.sleep(1000);					
         } catch (InterruptedException e) {
            blinker = null;
            return;
         }
      }
   }
}

bool gFlag = true;

Event sets flag to false, and causes thread to fall out of loop!
Simple but effective!


// while (true){

while ( gFlag ){

Don't sleep your thread so long.

If you need 1000ms timing then

int nSnooze = 1000;

while ( gFlag )
{
     Sleep(25);
     nSnooze -= 25;
    if (nSnooze > 0)
    {
        continue;
    }

     nSnooze = 1000;
     DoSomething();
}
commented: A simple and elegant solution that I made use of. +2

I created the boolean flag, but the problem is that it doesn't ever change. I want the WorkThread to run concurrently, but for some reason, the MouseListener doesn't react when the WorkThread is running. It's as if the WorkThread is monopolizing the program's resources, like it's not a separate thread at all, just an infinite loop in the main method.

I didn't mean for the thread to sleep for so long. I figure 10 ms should be enough, but I slowed the thread down for debugging.

gFlag is global.

In your event handler for mouse, set gFlag=false;

Thread falls out of while loop upon gFlag being false then exits.

There will be micro-delay between the flag being set and the thread reading the flag and falling out of its loop.

Just looked at your code again. Mouse event spawns the new thread?

Yes, the event handler spawns the WorkThread (I did not make this clear: aThread is an instance of WorkThread). When the WorkThread is running, it continuously updates the GUI, but it does not allow me to interact with JButtons, although they have listeners. Even if I try to quit, the program is not responding and I have to terminate it in the Task Manager.

My code now looks like this:

class Prog1() {

private boolean bFlag;
private WorkThread aThread;

public Prog1(args){
    ...
    addMouseListener(new MouseEventListener());
    aThread = new WorkThread();
    bFlag = false;
}

private class MouseEventListener extends MouseAdapter {
   public void mousePressed(MouseEvent e) {
      if(condition){
         bFlag = true;
         aThread.run();
      }
      else{
         // this does not interrupt the thread, since
         // I can't detect new mouse events in the WorkThread
          bFlag = false;
         aThread.interrupt();
      }
   }
}

...

private class workThread extends Thread {
   private volatile Thread blinker;
		
   public void run() {
      while (bFlag){
         try {
            doSomething();
            Thread.sleep(10);					
         } catch (InterruptedException e) {
            return;
         }
      }
   }
}
}

Where does <condition> come from? If its never cleared then the false logic won't be executed!

The condition is a boolean called isSelected. When the user clicks on a image displayed on the GUI, he selects an OrderedPair (another class I wrote) object. The GUI is then supposed to animate the selected object until the user clicks on a location to which to move it. So basically, the condition variable called isSelected is used to alternate behavior: the user selects an OrderedPair (the if(condition) part), then moves the OrderedPair to a new location (the else statement).

I know that there is no faulty logic, since the program ran fine before I added the WorkThread. The WorkThread is only used to animate the selected OrderedPair. I can select and move OrderedPairs, but I have to keep track of which OrderedPair I selected earlier. I know I can display the selected OrderedPair statically by swapping with a different image, but I thought it would look better with an animation and it is about time I stop avoiding writing programs with multiple threads.

I'm not sure that this is the issue, but just so you know, the while loop condition is only going to be checked after the method call that is inside the while loop completes. You probably knew that. Other than that, I'm not sure I understand what problem you're having. What you need to do is have a different thread (probably the main thread) detect the mouse event, then set a condition that lets the other thread know it's time to stop execution. The other thread should periodically check to see if it is time to stop execution.

In a nutshell, my problem is:
I can't get out of the while loop in the WorkThread.

To elaborate, the program runs fine without the WorkThread class, but once the WorkThread starts running, I can't interact with the GUI and trigger mouse events that should interrupt the WorkThread, even if it goes through multiple iterations of the while loop.

"I can't interact with the GUI and trigger mouse events that should interrupt the WorkThread, even if it goes through multiple iterations of the while loop."

So you're saying that once the WorkThread starts running, your program will not trigger mouse events? Or that your program triggers mouse events, but these mouse events do not interrupt the WorkThread like they're supposed to?

MY program won't trigger any mouse event once the WorkThread starts running. I had my event handler print a message every time it detected a mouse event and it only prints once, which indicated the thread is stuck in the while loop and is oblivious to the user interactions.

"I had my event handler print a message every time it detected a mouse event and it only prints once"

Like I said, you should have at least two threads: one would be your WorkThread, and the other would be your main thread, which presumably would run your code on the Event Dispatch Thread. The main thread would be the one responsible for the event handling. You should make sure that your code is running on the Event Dispatch Thread. . you can do so by calling SwingUtilities.isEventDispatchThread() from within the thread. Your "WorkThread" should return false when you call that method, and your main thread should return true when you call that method. So put that line of code into both your main thread code and your WorkThread code and tell me what it returns for each of them.

Btw, the reason I'm having you do that is because if your main code is running on the Event Dispatch Thread, like it should be, and if your "WorkThread" is also, which it should not be, then it could be blocking the thread, preventing any of your mouse clicks from registering. So I'm trying to make sure your Threads are actually set up correctly as separate Threads and that the one is running on the EDT. Thanks for being so patient.

I added the statement you mentioned in your previous post in three times: (1) in the main method of the outerProgram; (2) in the mousePressed method of the MouseEventListener in the inner program; (3) in the run method in the WorkThread.
(1) prints true, while (2) and (3) print false.
So for some reason, mousePressed works as the event handler, but once the WorkThread starts, it becomes the EDT and won't allow the MouseEventListener handle any incoming mouse clicks.

class OuterProgram() {

     public OuterProgram(){
           creates instance of inner program
           adds MouseEventListener to instance of inner program
     }

     main(){
         create window and set visible;
     }

}

class InnerProgram() {

private boolean bFlag;
private WorkThread aThread;

public InnerProgram(args){
    ...
    addMouseListener(new MouseEventListener());
    aThread = new WorkThread();
    bFlag = false;
}

private class MouseEventListener extends MouseAdapter {
   public void mousePressed(MouseEvent e) {
      if(condition){
         bFlag = true;
         aThread.run();
      }
      else{
         // this does not interrupt the thread, since
         // I can't detect new mouse events in the WorkThread
          bFlag = false;
         aThread.interrupt();
      }
   }
}

...

private class workThread extends Thread {
   private volatile Thread blinker;
		
   public void run() {
      while (bFlag){
         try {
            doSomething();
            Thread.sleep(10);					
         } catch (InterruptedException e) {
            return;
         }
      }
   }
}
}

WorkThread should not be running on the EDT. This indicates that WorkThread is not running in a separate thread - so the new Thread was not set up properly. Look up how to create a separate Thread on google. You should also look into Swing's WorkerThread class.

commented: Good troubleshooting skills. +2

Thanks for identifying the problem. I'll look in to in and post here if I have any more questions.

This whole loop-with-a- sleep-in-it polling approach is a poor way to go, even if you get it to work. You want your thread to go into a wait state and wait passively until notified to exit the wait, which it should do without further dalay. Have a look at wait() and notify() - you'll find loads of info via Google.

aThread.run();
is your problem. This calls the run method on the current thread.
You should use aThread.start(); twhich calls the run() method on a new thread

commented: Astute diagnosis. +2

Here's the update on what I've done:
I tried to mimic a Java tutorial example and have the WorkThread call run() within a main method. Unfortunately, this meant WorkThread had to be written as a static class and also I could not call a non-static method such as update(getGraphics()). If I didn't want WorkThread to be an inner class to avoid making it static, I wouldn't have been able to interact with the GUI,

So basically, the problem was that I started the WorkThread using aThread.run() (as mentioned above). What I should have done is use (new Thread(new WorkThread())).start(), where WorkThread implements Runnable instead of extending Thread.

Glad you found a solution. FYI, the easiest thing would have been to leave all your code as was (extending Thread), and simply call
new WorkThread.start();

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.