Stopping Thread B when Thread A completes with a Condition

I have a long running operation in my AplotPDFDialog Dialog.  So I want to show the user a Progress Bar to let them know the operation is in progress.  Mainly because they can not continue to work until the operation completes.

Here are the 3 classes:
The base dialog class  =   AplotPDFDialog
  SubClass -  The operation class  =      MyOperationListener
  SubClass  - The Progress Bar class =  ProgressBarThread

This is how I have it working today.

The  startSavePdfOperation method in the Dialog class is called by a button click.


private void startSavePdfOperation() {
Display.getDefault().asyncExec(new Runnable() {
         public void run() {
            startProgressBar();
         }
      });
      saveOp = new AplotSaveOperation(appReg.getString("aplot.message.SAVETOPDF"), "PDF", session);
      saveOp.addOperationListener(new MyOperationListener(this) { 
        
         public void endOperationImpl() {
            java.io.File zipFile = null;
            try {               
               AplotSaveResultsParser.SaveResult saveResults = saveOp.getSaveResults();
               if (saveResults != null) {
                  if (!saveResults.hasZipFile) {
                     StringBuffer sb = new StringBuffer();
                     sb.append(saveResults.error);
                     sb.append(":\n");
                     for (int i = 0; i < saveResults.datasetSaveResults.size(); ++i) {
                        AplotSaveResultsParser.DatasetSaveResult dsr = (AplotSaveResultsParser.DatasetSaveResult) saveResults.datasetSaveResults.get(i);
                        sb.append(dsr.fileInZipOrError);
                        sb.append("\n");
                     }
                     throw new RuntimeException(sb.toString());
                  }
                  zipFile = saveOp.getZipFile(saveResults);
                 //addSaveResults(saveResults);
                  performRenameOperation(zipFile, saveResults);
               } // end if
            } // end try
            catch (Exception e) {
               e.printStackTrace();
            }
            finally {
               saveOp.removeOperationListener(this);
               saveOp = null;
               if (zipFile != null) {
                  try { zipFile.delete(); } catch (Exception e) {}
               }
               Display.getDefault().asyncExec(new Runnable() {
                  public void run() {
                    baseDialog.clearArrays();
                 }
               });
            }
         }
      });
      session.queueOperation(saveOp);
   } // end startSavePdfOperation()

Open in new window


At the very start of the method I am Starting the Progress Bar in a separate thread.

Display.getDefault().asyncExec(new Runnable() {
         public void run() {
            startProgressBar();
         }
      });

Open in new window


Method for ProgressBar

 public void startProgressBar() {
      try {
         new ProgressMonitorDialog(getShell()).run(true, false,
            new ProgressBarThread());
      } 
      catch (InvocationTargetException e) {
         MessageDialog.openError(getShell(), "Error", e.getMessage());
      } 
      catch (InterruptedException e) {
         MessageDialog.openInformation(getShell(), "Cancelled", e.getMessage());
      }
   }

Open in new window


ProgressBar Class

class ProgressBarThread implements IRunnableWithProgress  {
      private static final int TOTAL_TIME = 10000;
      private static final int INCREMENT = 1000;
      
      public ProgressBarThread() {
         
      }
      
      public void run(IProgressMonitor monitor) throws InvocationTargetException,InterruptedException {
         monitor.beginTask("Creating PDF File(s)", IProgressMonitor.UNKNOWN);
         for (int total = 0; total < TOTAL_TIME ; total += INCREMENT) {
            Thread.sleep(INCREMENT);
            monitor.worked(INCREMENT);
            if (total == TOTAL_TIME / 2) monitor.subTask("Please be patient... Operation should finish soon.");
        }
        monitor.done();
        
      }

Open in new window



Then the listener is added to the long running operation. See Method Above

saveOp.addOperationListener(new MyOperationListener(this)

Open in new window


MyOperationListener Class

public abstract class MyOperationListener implements InterfaceAIFOperationListener {
      AplotCreatePDFDialog w = null;
           
      public MyOperationListener(AplotCreatePDFDialog win) {
         w = win;
      } 
          
      public void startOperation(String startMessage) {
         Display.getDefault().asyncExec(new Runnable() {
            public void run() {
               //w.startProgressBar();
               w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
               w.recursiveSetEnabled(getShell(), getShell().getEnabled());
               w.getShell().setEnabled(!getShell().getEnabled());
            }
         });
      } 

      public void endOperation() {
         try {
            endOperationImpl();
         }
         finally {
            Display.getDefault().asyncExec(new Runnable() {
               public void run() {
                  w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_ARROW));
                  w.recursiveSetEnabled(getShell(), true);
                  w.getShell().setEnabled(!getShell().getEnabled());
                  w.close();
               }
            });
         }
      } 
      abstract protected void endOperationImpl();
   } 

Open in new window



1.  The operation can run any where from 6 seconds to over 20 seconds.  There is not a average time for the operation.

2.  So I had to set the Progress Bar up to run off and timer.
private static final int TOTAL_TIME = 10000;
 for (int total = 0; total < TOTAL_TIME ; total += INCREMENT)

Open in new window


3.  The problem is that the operation is running on 1 Thread and the progress bar is running on thread 2.  The two threads do not correspond together.  

4.  If the operation finishes before the progress bar timer is complete.  The progress bar runs in the background until the timer expires.  If the Progress Bar timer expires before the operation is complete.  The user thinks they can continue to work, but that is not true.

Someone suggested using a Condition in the progress bar and have the operation listener to update the condition when the operation is over.  So it will stop the Progress Bar thread.

Progress Bar Class with the Condition

Class ProgressBarThread implements IRunnableWithProgress
{
    private static final int TOTAL_TIME = 5000;
    private static final int INCREMENT = 1000;

    private Condition done = null;

    public ProgressBarThread(Condition done)
    {
        this.done = done;
    }

    public void run(IProgressMonitor monitor) throws InvocationTargetException,InterruptedException
    {
        monitor.beginTask("Sending Plot", IProgressMonitor.UNKNOWN);
        for (int total = 0; total < TOTAL_TIME ; total += INCREMENT)
        {
            if (done.await(INCREMENT, TimeUnit.MILLISECONDS))
            {
                break;
            }
            monitor.worked(INCREMENT);
            if (total == TOTAL_TIME / 2) monitor.subTask("Please be patient... Operation should finish soon.");
        }
        monitor.done();
    }
}

Open in new window


Then doing this to the operation class

AplotPlotterDialog w = null;

Condition done = null;

public MyOperationListener(AplotPlotterDialog win)
{
    w = win;
    Lock lock = new ReentrantLock();
    done = lock.newCondition();
} 

public void startProgressBar()
{
    try
    {
        new ProgressMonitorDialog(getShell()).run(true, false,
        new ProgressBarThread(done));
    } 
    catch (InvocationTargetException e)
    {
        MessageDialog.openError(getShell(), "Error", e.getMessage());
    }  
    catch (InterruptedException e)
    {
        MessageDialog.openInformation(getShell(), "Cancelled", e.getMessage());
    }
}

public void endOperation()
{
    try
    {
        endOperationImpl();
    }
    finally
    {
        Display.getDefault().asyncExec(new Runnable() {
        public void run() {
        w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_ARROW));
        w.recursiveSetEnabled(getShell(), true);
        w.getShell().setEnabled(!getShell().getEnabled());
        done.signal();
        w.close();
    }
    });
    }
}

Open in new window


But I can not get this to work.  The operation listener has to have a startOperation Method and the code above has replaced.

Any Help of This?
jkteaterAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

krakatoaCommented:
3.  The problem is that the operation is running on 1 Thread and the progress bar is running on thread 2.  The two threads do not correspond together.  

Why not? They should; then your problem will be over. Set a flag.
0
jkteaterAuthor Commented:
Please show me how to set a flag.  I have three over places in my project that is having the same problem with  the threads, so that would be such a great help to me.
0
krakatoaCommented:
Well normally as you know, a thread will end when the run method is over. Leaving aside the deprecated termination options, a thread's run() method is best halted by a boolean conditional being set to false, and that's all a flag is. So another thread can set that flag either directly (boolean stoprunning  = true (for example)) or indirectly via a setter method doing the same thing.
0
Exploring SharePoint 2016

Explore SharePoint 2016, the web-based, collaborative platform that integrates with Microsoft Office to provide intranets, secure document management, and collaboration so you can develop your online and offline capabilities.

jkteaterAuthor Commented:
How about when the code is like this?

I have 3 classes.

Dialog Class
Operation Class
Progress Class

Dialog Class - Method to start long running operation

private void startPrinterListOperation() {
      listOp = new AplotPrinterListOperation(appReg.getString("aplot.message.GETPRINTERLIST"), session);
      listOp.addOperationListener(new AplotOperationListener(this) {
         public void endOperationImpl() {
            try { etc......

Open in new window


Adding the OperationListener to the operation

listOp.addOperationListener(new AplotOperationListener(this) {

Open in new window


public abstract class AplotOperationListener implements InterfaceAIFOperationListener {
   Dialog w = null;
  
   public AplotOperationListener(Dialog dialog) {
      w = dialog;
   } 

   public void startOperation(String startMessage) {
      Display.getDefault().asyncExec(new Runnable() {
         public void run() {
            w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
            w.getShell().setEnabled(false);
         }
      });
   } 
public void endOperation() {
      try { etc.......

Open in new window


Can I start the PorgressBar class from the OperationListener Class?

Something like :

public abstract class AplotOperationListener implements InterfaceAIFOperationListener {
   Dialog w = null;
  
   public AplotOperationListener(Dialog dialog) {
      w = dialog;
   } 
   
   public void startProgressBar() {
      try {
         new ProgressMonitorDialog(getShell()).run(true, false,
            new ProgressBar());
      } 
      catch (InvocationTargetException e) {
         MessageDialog.openError(getShell(), "Error", e.getMessage());
      } 
      catch (InterruptedException e) {
         MessageDialog.openInformation(getShell(), "Cancelled", e.getMessage());
      }
   }

   public void startOperation(String startMessage) {
      Display.getDefault().asyncExec(new Runnable() {
         public void run() {
            startProgressBar();
            w.getShell().setCursor(new Cursor(Display.getCurrent(), SWT.CURSOR_WAIT));
            w.getShell().setEnabled(false);
         }
      });
   } 

Open in new window


Then some how set a flag for progressbar to stop when the operationlistener closes the dialog


I really need some help with the above.  Can you please show some code to help me understand better?
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jkteaterAuthor Commented:
I am not using swing.  My code is in SWT.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.