Solved

Stopping Thread B when Thread A completes with a Condition

Posted on 2013-01-14
6
260 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
  • 3
  • 3
6 Comments
 
LVL 16

Expert Comment

by:krakatoa
Comment Utility
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
Comment Utility
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 16

Expert Comment

by:krakatoa
Comment Utility
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:jkteater
Comment Utility
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 16

Accepted Solution

by:
krakatoa earned 500 total points
Comment Utility
0
 

Author Comment

by:jkteater
Comment Utility
I am not using swing.  My code is in SWT.
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

An old method to applying the Singleton pattern in your Java code is to check if a static instance, defined in the same class that needs to be instantiated once and only once, is null and then create a new instance; otherwise, the pre-existing insta…
Java functions are among the best things for programmers to work with as Java sites can be very easy to read and prepare. Java especially simplifies many processes in the coding industry as it helps integrate many forms of technology and different d…
Viewers learn about the “while” loop and how to utilize it correctly in Java. Additionally, viewers begin exploring how to include conditional statements within a while loop and avoid an endless loop. Define While Loop: Basic Example: Explanatio…
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…

744 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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now