Solved

Stopping Thread B when Thread A completes with a Condition

Posted on 2013-01-14
6
268 Views
Last Modified: 2013-02-05
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?
0
Comment
Question by:jkteater
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 3
6 Comments
 
LVL 17

Expert Comment

by:krakatoa
ID: 38775130
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
 

Author Comment

by:jkteater
ID: 38776067
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
 
LVL 17

Expert Comment

by:krakatoa
ID: 38776202
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
What Is Transaction Monitoring and who needs it?

Synthetic Transaction Monitoring that you need for the day to day, which ensures your business website keeps running optimally, and that there is no downtime to impact your customer experience.

 

Author Comment

by:jkteater
ID: 38787929
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
 
LVL 17

Accepted Solution

by:
krakatoa earned 500 total points
ID: 38788960
0
 

Author Comment

by:jkteater
ID: 38827076
I am not using swing.  My code is in SWT.
0

Featured Post

Enroll in June's Course of the Month

June's Course of the Month is now available! Every 10 seconds, a consumer gets hit with ransomware. Refresh your knowledge of ransomware best practices by enrolling in this month's complimentary course for Premium Members, Team Accounts, and Qualified Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This was posted to the Netbeans forum a Feb, 2010 and I also sent it to Verisign. Who didn't help much in my struggles to get my application signed. ------------------------- Start The idea here is to target your cell phones with the correct…
Introduction Java can be integrated with native programs using an interface called JNI(Java Native Interface). Native programs are programs which can directly run on the processor. JNI is simply a naming and calling convention so that the JVM (Java…
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …

695 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question