views:

94

answers:

4

I have a bit of a problem. I have a java application and when it starts it needs to make around six maybe seven threads that just wait for some sort of event to occur (i.e. user presses a button). An example of how I make these threads is below. The problem is, I open my task manager only to see that all my four cpu cores are at 100% (up from around 20), as soon as I close my application everything returns to normal. I am still new to multi-threading and I know I am committing some sort of concurrency sin here but I would appreciate any insight on how to rectify this situation.

new Thread (new Runnable() { public void run()
{
    while (true)
        if (doSomeFunction)
        {
            myFunction();
            doSomeFunction = false;
        }
} } ).start();

// Somewhere else in the code
doSomeFunction = true;

I am thinking perhaps wait and notify would be the right approch to doing this?

EDIT: Just for clarification, this has nothing to do with powering swing components. Instead this does events based on a script, I don't want certain script functions to block but instead return immediately while finishing the task in the background.

+5  A: 

There are two possible answers here.

The first is that you are waiting for a button press in a Swing application (or similar). If so, threads aren't the answer. You should simply be using an action listener:

JButton button = ...
button.addActionListener(new ActionListener() {
  void actionPerformed(ActionEvent e) {
    // do stuff
  }
});

You need to be really careful about using threads in Swing applications. That's because only one thread (called the Event Dispatching Thread or EDT) is the only thread allowed to make UI updates. All event handlers occur in the EDT. So while code is running on the EDT no UI updates will happen (moving/closing windows, pressing buttons, etc) so EDT code should be short-lived.

The more general problem can be solved in a number of ways that depend on more information than is provided.

Firstly, to answer your question: your CPU usage is going to 100% because the threads are constantly checking the value and calling a function in an endless loop.

You should be using the Java 5+ concurrency model however, which will look something more like this:

ExecutorService threadPool = Executors.newFixedThreadPool(10); // or whatever
threadPool.submit(new Runnable() {
  public void run() {
    // do stuff
  }
});

As to how to do the inter-thread communication, that's where it gets tricky. You're sharing a primitive variable, which is a really bad idea.

The simplest idiom is to use wait-notify:

final Object someObject = ...
ExecutorService threadPool = Executors.newFixedThreadPool(10); // or whatever
threadPool.submit(new Runnable() {
  public void run() {
    synchronized (someObject) {
      someObject.wait();
    }
    // do stuff
  }
});
...
synchronized (someObject) {
  someObject.notify(); // wakes ONE waiting thread
}

The synchronized mutexes are really important.

But Java 5 adds a whole bunch of alternatives to this. I would recommend buying Java Concurrency in Practice and reading it cover to cover.

cletus
+1: With Swing it's worth mentioning that there is a dedicated thread that dispatches events to the ActionListener (and other callback classes), which is why there's no need to create your own.
Adamski
@Cletus: This looks like a good model, however I have a few questions. what exactly is someObject and what happens if I want to run it more than once, as in my example I want to run the function myFunction() whenever nessesary.
Dave
@Dave `someObject` is any object. Technically it's called a *monitor*. You can use a custom object to communicate data between threads or, if there's no need for that, just use: `Object someObject = new Object();`. You can also embed the body of that `run()` method in a `while (true) { ... }` loop or similar if you want to do it multiple times.
cletus
@Dave you may need to consider issues like "what should happen if the code in the thread is executing and you call `notify()` again?". Depending on the answer to that question it may be more appropriate to use a different signalling method.
cletus
+1  A: 

At the end of your while loop, you should have something like Thread.sleep(250). That causes the current thread to sleep for 250 milliseconds so that it's not burning up CPU just looping.

Jon
+3  A: 

What you are doing is called Busy waiting. The quick-and-dirty fix would be to add a Thread.sleep(1) to the code. This should already be enough to bring the cpu utilization down.

However the correct solution would be to use proper synchronization techniques e.g. a Semaphore

Wolfgang
+4  A: 

If you are trying to control when all of your threads actually begin their work, the CountDownLatch introduced int Java 5 may be an easy solution:

public void static main(String[] args) {
  final CountDownLatch signalToDoSomeFunction = new CountDownLatch(1);

  new Thread(new Runnable() {
    public void run() {
      // wait until the latch is "counted down"
      signalToDoSomeFunction.await();
      myFunction();
    });

  // create other threads similarly

  // all thread created but waiting, now ready to start work
  signalToDoSomeFunction.countDown();

}

This eliminates the inifinte loop. The CountDownLatch hides Object.wait() and Object.notify() calls behind a much nicer interface.

Jim