Heavy math routines and separate threads?


DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Results 1 to 14 of 14

Thread: Heavy math routines and separate threads?

Hybrid View

  1. #1
    Join Date
    Jul 2004
    Posts
    54

    Heavy math routines and separate threads?

    I have a number of heavy math/cpu usage routines and gather it would be good to make them separate threads so things like JProgressBar and other stuff will work correctly.

    Is this all I need to do to make them runnable in their own threads?

    final Runnable HM = new Runnable()
    {
    public void run()
    {
    heavy_math(x, y, z);
    }
    };

    Is there a general method I could call before and after a heavy math routine that would do the same thing?

    Is it possible that the threads will get out of sync?


    I haven't gotten a handle on this thread stuff yet so I must ask dumb questions.

    RON C

  2. #2
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560

    Thread..

    I have never seen that way of implementing a thread (or two).
    Here is a bare-bone example:

    Code:
    public class ThreadExample  implements Runnable {
      Thread t1=null;
      Thread t2=null;
      private boolean t1IsRunning=false;
      private boolean t2IsRunning=false;
    
      public ThreadExample() {
      }
      public void gogogo() {
        t1=new Thread(this); // not started yet.... 
        t2=new Thread(this); // not started yet.... 
        setT1IsRunning(true); // not started yet.... 
        setT2IsRunning(true); // not started yet.... 
        t1.setPriority(Thread.NORM_PRIORITY); // not started yet.... 
        t2.setPriority(Thread.NORM_PRIORITY); // not started yet.... 
        t1.start(); // STARTED
        t2.start(); // STARTED
      }
      /**
       * Thread control methods
       */
      private synchronized boolean getT1Running() {
        return t1IsRunning;
      }
      private synchronized void setT1IsRunning(boolean t1IsRunning) {
        this.t1IsRunning=t1IsRunning;
      }
      private synchronized boolean getT2Running() {
        return t2IsRunning;
      }
      private synchronized void setT2IsRunning(boolean t2IsRunning) {
        this.t2IsRunning=t2IsRunning;
      }
      public void heavy_math1(int x, int y, int z) {
        /**
         * Do some heavy math....
         */
        setT1IsRunning(false); // then finish
        return;
      }
      public void heavy_math2(int x, int y, int z) {
        /**
         * Do some heavy math....
         */
        setT2IsRunning(false); // then finish
        return;
    
      }
    
      /**
       * This method is called from the java VM.  If you call it from within the
       * code of a class it will not be a thread....
       * The java VM runs this in 'bursts'
       * lending the cpu power to the threads in a round-robin fashion.
       * - if you view the processing performed by the two heavy_math -methods
       * as two sequences (threads) of statement executions, then the processing done
       * by heavy_math1 is halted (in its 'tracks') while heavy_math2 is allowed to
       * continue.
       *
       * If you want to set or get any values that are used by the threads you must
       * do it via synchronized methods, like the control methods above.  Remember,
       * synchronization has a bill to pay in cpu-power, so it should not be used
       * unless it is required.
       *
       * If the heavy_math methods access progressbars (or any other vizualization
       * components) in the GUI, then they will be responsive, since the GUI is
       * under the control of the applications main thread, wich is also executed in
       * bursts by the java VM.
       *
       * NOTE: avoid Thread.MAX_PRIORITY, unless you want to block out your PC....
       */
      public void run () {
        if (Thread.currentThread()==t1) {
          while (getT1Running()) {
            heavy_math1(1,2,3);
          }
          return; // the death of t1
        } else if (Thread.currentThread()==t2) {
          while (getT2Running()) {
            heavy_math2(4,5,6);
          }
        }
        return; // the death of t2
      }
      public static void main(String[] args) {
        ThreadExample te = new ThreadExample();
        te.gogogo();
      }
    
    }
    Last edited by sjalle; 03-14-2005 at 01:50 PM.
    eschew obfuscation

  3. #3
    Join Date
    Mar 2005
    Location
    Sendling, MUC, .de
    Posts
    100
    What rechmbrs is doing is defining and instantiating an inner class that implements the interface Runnable "in one shot". But he does not start any thread which you (afterwards) would do like
    Code:
    new Thread(HM).start();
    This is correct java syntax although not good style (referring to instances with upper case starting names). It is kind of a shortcut for first defining an inner class like
    Code:
    (static) class MyRunnable {
      public void run {
        //heavy math here
      }
    }
    (in the scope of the enclosing class)
    and afterwards instantiating it like
    Code:
    Runnable HM = new MyRunnable();
    (in the scope of a (static) method). See, I had to introduce the name "MyRunnable" I'd never use again. That's the savings you make with the shortcurt.

    So the answer to the original question
    Is this all I need to do to make them runnable in their own threads?
    ...is: yes. You made it runnable; you'd only have to start a Thread that executes this Runnable now.
    The purpose of the Runnable interface is to provide a means to have classes executed as threads that cannot subclass Thread eg. because they need to subclass some other class (there is no multiple inheritance in java).

    You even do not need the class to be named; you can use an anonymous one like
    Code:
    new Thread(
        new Runnable() {
          public void run() {
            System.out.println("doing my best to do heavy math stuff");
          }
        }
    ).start();
    in a method to start a thread executing your heavy math stuff concurrently.

    ---

    Making your threads behave "civilized", ie. the way you want them to behave/interact, is quite a different topic and non-trivial. Stopping threads you do as sjalle has shown (DO NOT use Thread.stop() and the like! They're deprecated for a reason).
    But as long as it's simply about reading access like for a JProgressBar where it is non-vital to see an object in a consistent state (that state is obsolete the very second after) or you even access only primitive type attributes (access to which is atomic anyway*) no synchronisation at all is required.

    If that's all you want to do, then it's fine. For the more sophisticated situations there has been done quite some brainwork; look at the results of this brainwork in the concurrency API java.util.concurrent (since 1.5) and decide yourself.

    ---
    *footnote: that's why sjalle's way to stop a thread is the recommended one and working.
    Last edited by meisl; 03-15-2005 at 06:21 PM.

  4. #4
    Join Date
    Jul 2004
    Posts
    54
    This is an example of what I ended up doing.

    Comments, recommendations???

    RON C

    class RunHeavyMath implements Runnable
    {
    private float x[];
    private float y[];
    private int z;
    private int flag;
    private int opt = 1;
    public void run()
    {
    if (opt == 1)
    heavy_math_p(x, y, z);
    if (opt == 2)
    heavy_math_t(x, y, z);
    }
    private void heavy_math_p(float x[], float y[], int z)
    {
    flag = 0;
    int l = x.length;
    int m = y.length;
    if (l != m)
    flag = -1;
    int ndx;
    for (ndx = 0; ndx < l; ndx++)
    {
    y[ndx] = x[ndx] + (float) z;
    }
    flag = 1;
    }
    private void heavy_math_t(float x[], float y[], int z)
    {
    flag = 0;
    int l = x.length;
    int m = y.length;
    if (l != m)
    flag = -1;
    int ndx;
    for (ndx = 0; ndx < l; ndx++)
    {
    y[ndx] = x[ndx] * (float) z;
    }
    flag = 1;
    }
    public void executeHeavyMath()
    {
    Thread t = new Thread(this);
    t.start();
    }
    private void setX(float X[])
    {
    x = X;
    }
    private void setY(float Y[])
    {
    y = Y;
    }
    private void setZ(int iz)
    {
    z = iz;
    }
    private void setO(int io)
    {
    opt = io;
    }
    private int getF()
    {
    return flag;
    }
    //
    static public void main(String[] args)
    {
    System.out.println("Start ");
    int flagrr = 0;
    int flagss = 0;
    int l = 10;
    float xrr[] = new float[l];
    float yrr[] = new float[l];
    float xss[] = new float[l];
    float yss[] = new float[l];
    int ndx;
    for (ndx = 0; ndx < l; ndx++)
    {
    xrr[ndx] = 1.0f;
    yrr[ndx] = 0.0f;
    xss[ndx] = 5.0f;
    yss[ndx] = 0.0f;
    System.out.println("A: " + ndx + " " + xrr[ndx] + " " + yrr[ndx]
    + " " + xss[ndx] + " " + yss[ndx]);
    }
    RunHeavyMath rr = new RunHeavyMath();
    rr.setX(xrr);
    rr.setY(yrr);
    rr.setZ(30);
    rr.setO(1);
    rr.executeHeavyMath();

    RunHeavyMath ss = new RunHeavyMath();
    ss.setX(xss);
    ss.setY(yss);
    ss.setZ(50);
    ss.setO(2);
    ss.executeHeavyMath();
    //
    while (flagrr == 0 && flagss == 0)
    {
    flagrr = rr.getF();
    flagss = ss.getF();
    }
    for (ndx = 0; ndx < l; ndx++)
    {
    System.out.println("B: " + ndx + " " + xrr[ndx] + " " + yrr[ndx]
    + " " + xss[ndx] + " " + yss[ndx]);
    }
    System.out.println("End ");
    }
    }

  5. #5
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560

    Just one thing:

    I don't like inner classes, cause I don't like bloated syntax. I think adapters
    suck too and I really hope that Java doesn't end up like C++.... But then
    again, I'm just an old fart that spent his first 15 years of programming coding
    Fortran.

    The documentation on why the stop() method is deprecated is still
    at the same place as the doc for the java.lang.Thread.stop() method.

    PS: My synchronization habit is from 16 bit computing, when you ran the risk
    of halting a thread while it was busy processing a 32 bit primitive, - only
    half of the value could ride the bus at one time.
    Last edited by sjalle; 03-15-2005 at 07:13 PM.
    eschew obfuscation

  6. #6
    Join Date
    Mar 2005
    Location
    Sendling, MUC, .de
    Posts
    100
    Fortran, ...
    Yeah, 'K sjalle, I got it. IMHO it's not a matter of taste but simply about understanding how things work. Only after that one can - but need not - discuss "style".

    Doc on stop()
    Maybe it's a bit short there. But there's the lang-spec and the spec of the JVM as well.

    Synchronization
    ...so we see: what our fathers and grandfathers did wasn't too bad anyway... ;-)
    Last edited by meisl; 03-15-2005 at 08:05 PM.

  7. #7
    Join Date
    Mar 2005
    Location
    Sendling, MUC, .de
    Posts
    100
    Erm, rchmbrs, could you please summarize in one sentence what your heavy math stuff is about?

  8. #8
    Join Date
    Jul 2004
    Posts
    54
    Meisl,
    I started the thread asking about heavymath/cpu routines and finally got something that seems to work from the standpoint of using another thread but the equivalent code trying to put JProgressBar calls still doesn't work. Am I missing something?

    FYI. I programmed in Fortran until 2002 and started way back in 1959 with Fortran II on an IBM 1620.

    RON C

  9. #9
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560

    meisl, there is a bit more on deprecated Thread methods here:

    Maybe it's a bit short there. But there's the lang-spec and the spec of the JVM as well
    See the attatched copy from the java doc
    Attached Files Attached Files
    eschew obfuscation

  10. #10
    Join Date
    Jul 2004
    Posts
    54
    SJalle,

    Thanks for the primitive. I'll try to read and try to understand.

    As I'm under a time chrunch, does someone in the nearterm have an example of how I might be able to use JProgressbar and the type of code I supplied above.

    I have so much to learn as I've never played much with guis and the threading associated. I have used threads for multiprocessing - as noted appove.

    Thanks,
    RON C

  11. #11
    Join Date
    Mar 2005
    Location
    Sendling, MUC, .de
    Posts
    100

    little demo to play around with

    Hey Ron,
    I have put together a little demo that uses various threads, two of them doing "heavy math stuff". The progress of these two is displayed via JProgressBars and there are buttons to start, stop, suspend, resume one or both. On STDOUT it prints messages about what happens including information in which thread something happened.

    The methods stop(), suspend() and resume() in class HeavyMathCalculator implement the suggested patterns while avoiding Thread.stop(), Thread.suspend() and Thread.resume().

    I'm sorry that all is quite complicated, but maybe you can nonetheless adapt it for your purpose. It's grown out of size mostly because of those bloody buttons, that you would not need in your app I guess.
    In any case, I'd like to recommend the chapters on Threads and Progress Bars in the Java Tutorial, that may be easier to understand than the technical papers, including the javadoc on Thread primitive deprecation.

    There is a built-in test in this demo:
    After it has started, click the following buttons:
    1. "start/resume both"
    2. "math1.stop()"
    3. "suspend both"
    4. "math1.resume()"
    What is going on here?! Can you repair this?

    Well, maybe I should add that in fact there is a general flaw in my conceptual design of the buttons...

    Anyways, have fun with it.

    p.s.: I'm still interested in what your heavy math stuff is calculating.
    Attached Files Attached Files
    Last edited by meisl; 03-17-2005 at 11:43 AM.

  12. #12
    Join Date
    Jul 2004
    Posts
    54
    meisl,

    Thanks for the help.

    My program is different in that the dialog is built and buttons on it tell what to do. The program is like an image editing program but has a very special use.

    My heavymath ranges from simple convolution to iterations of random numbers then convolution then tied to the image. I'd be willing to send the code (somewhat large) put prefer it not be spread around. If interested, send me a message.

    Thanks,
    RON C.

  13. #13
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560

    meisl, just out of curiosity...

    Can't this:

    Thread.sleep( 10 + new Random().nextInt(100) ); // give other threads time to do their work

    be replaced with this:

    Thread.currentThread().yield();

    at strategic places in the heavy math code, - or nothing to halt it at all, -
    just threads running with normal priority ?

    As it is now, the sleeping is there just to show the progressbars progressing...

    And why must the GUI be made by a new thread, what is wrong with
    just makeing the GUI - in the programs main thread ?
    I did this, with no visible difference to the execution:

    Code:
    public ThreadProgressDemo(boolean isVerbose) {
      this.isVerbose = isVerbose;
      createAndShowGUI();
      System.out.println("GUI created");
    }
    Last edited by sjalle; 03-17-2005 at 02:33 PM.
    eschew obfuscation

  14. #14
    Join Date
    Mar 2005
    Location
    Sendling, MUC, .de
    Posts
    100
    Sorry, I haven't had too much time left lately.

    Anyway, you're quite right wrt to Thread.sleep() vs Thread.yield(), sjalle. It's fine and much less typing - when it's all about equal-priority threads. But if you have threads with (possibly*) different priorities, you cannot give a lower-prioritized thread the chance to execute via Thread.yield(). This is due to java's so-called fixed-priority thread scheduling algorithm. The same goes for no precaution at all in your code: only threads with the same priority as the currently executing thread eventually get a chance - and if a thread with higher priority becomes runnable, none of the former will be executed as long as the higher-prioritized thread has finished.
    So sleep() is the most general approach and that's why I used it in the demo.

    Well, and of course I have indeed been too lazy to facilitate some heavy math, so you're completely right with regard to the progress bars/Thread.sleep(). I had been thinking about tweeking the whole thing with Mandelbrot set computation - a perfectly parallelizable problem - but that would have led way too far in this context I guess.

    GUI-from-event-dispatching-thread-thing:
    I have not fully understood this myself, but I did occasionally experience the deadlocks they're talking about when doing GUI-stuff from the main thread. It has something to do with modifying (swing-)components that had already been "realized" (mainly: painted onscreen); where modifying even includes eg changing the contents of a text-field. Such deadlocks typically manifest themselves in an app getting stuck at startup with no window coming up (ie. sometimes, as with most effects related to concurrency).
    For a similar reason I use invokeAndWait() instead of invokeLater(), although it admittedly looks quite odd; even more with the possible exceptions to catch...
    Note that I do start() the demo from the main thread (hence the thread that polls the HeavyMathCalculators is a child of main), where components are eventually modified. That's ok, problems seem to occur if you do both, creation ("realization") AND modification of the components from main, or: creation from main and modification from event-dispatch, eg in an event handler.
    Additionally, with Win98 and older JDKs, I had a queer effect on the cpu usage display: it was always at 100%, even if nothing was done except waiting for some input event. Doing the GUI stuff from the event-dispatch thread fixed it. However, since 1.4 (if I recall it correctly), this behaviour does not occur anymore.
    But as already said, all that I don't really understand.

    Ah, and hey: there is no new Thread that creates the GUI. The event-dispatching thread is always there when using awt/swing. The new thread (as mentioned this is a child of main), that changes the GUI - well this one isn't essential. But while we're at it I thought...

    ---------------
    * footnote: at last, a thread's priority can change during its life cycle


    @Ron:
    I didn't get in what your program is (principally) different. There are buttons to click in the demo as well... Ok, doesn't seem too important.
    Your image manipulation stuff sounds interesting. I have seen that you asked some questions about JAI elsewhere here - and that there hasn't been much of a response. I've been playing around with that some time ago but didn't do anything big. Especially that rendering-graph paradigm or what's it called I found interesting. I heard there's a major revision of JAI out now, 2.0 or so.
    Well, enough of chatting around. Was the demo of any help for you?
    Last edited by meisl; 03-22-2005 at 04:59 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center