3

I'd like to know how to call different functions cross thread in Java. Right now the way I'm doing it is to write my run() function of my thread as so

public volatile boolean invokeMyFunction = false;

public void run() {
    while(true) { 
        if(invokeMyFunction) {
            MyFunction();
            invokeMyFunction = false;
        }
    }
}

and if I want to run the function MyFunction() from outside that thread write "whateverobject.invokeMyFunction = true" and it will run my function from within the thread because that loop will pick it up. This works great for me, but it uses 100% of my CPU because of that while(true) loop. I could fix that by just slapping a Thread.sleep(1000) inside the loop but that seems messy and I can't help but to believe there's a better way of doing this.

David Zorychta
  • 13,039
  • 6
  • 45
  • 81
  • Is it possible that there is going to be more than one function call? Do you need a solution that can call an arbitrary amount of functions on the second thread? –  Dec 20 '11 at 05:58
  • Ideally I would love a solution which allows multiple calls to multiple functions on the second thread, yes – David Zorychta Dec 20 '11 at 18:52

4 Answers4

4

I think here, the easiest and CPU-friendly way to achieve this is

public void run() {
    while(true) { 
        synchronized(foo) {
            while(!invokeMyFunction) {
                foo.wait();
            }
        }
        MyFunction();
        invokeMyFunction = false;
    }
}

The above code runs in it's own Thread. Another thread can do this to let the first Thread run MyFunction():

invokeMyFunction = true;
foo.notifyAll();

Note that a) You cannot make invokeMyFunction a Boolean and synchronize over it because there are only two Booleans in all of java :) b) If invokeMyFunction is set n times, it might still run fewer times if invokeMyFunction is set to true while it was not false. c) Using a BlockingQueue might be easier and would allow Thread 1 to run arbitrary functions:

while(true) {
    Runnable next = queue.take();
    next.run()
}

And another thread would tell it to run MyFunction like this:

queue.put(new Runnable() {
    void run() {
        MyFunction();
    }
});

Seems easier to me :) Also, if you then want n Threads to run whatever comes through the queue, you just need to spawn n Threads that listen on the queue. Or you can learn how to use thread pools: http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html

Note:

queue.put() blocks until a new space is available in the BlockingQueue, i.e. it blocks if it is "full". See the implementation docs of whatever BlockingQueue implementation you are using to see if your queue has a limit. In any case, make sure you're not adding more items to work with than you can process for too long.

Kosta
  • 812
  • 1
  • 7
  • 13
2

You can put a monitor in your thread, and wait on that monitor. When you invoke the function, tell the monitor to release someone from it (and it should only have that one) who can run your function and then go back to waiting again.

On the flip side, there's nothing inherently wrong with the sleep route either. I see why you would call it messy, but it runs a lower chance of making a silly mistake and provides for looser coupling between your services.

(Side note - you don't need to put a monitor in the thread. You could use that object as the monitor instead of an internal monitor. But then you open yourself up to someone else potentially interfering with it, so it's best to use a private internal Object as your monitor.)

corsiKa
  • 81,495
  • 25
  • 153
  • 204
2

There are several holes in your code, apart from the fact that you are going to hog the cpu.

What if your other threads wants this thread to invoke twice within the time it takes MyFunction to execute? You would end up missing one invocation.

An improvement could be:

public volatile boolean invokeMyFunction = false;

public void run() {
    while(true) { 
        if(invokeMyFunction) {
            // Moved here.
            invokeMyFunction = false;
            MyFunction();
        }
    }
}

However, this only makes the race condition less likely, not impossible.

You may be better off using a BlockingQueue like I have suggested here. Make the other thread post something in a queue which is read by this thread. You would also not hog the cpu that way.

Community
  • 1
  • 1
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
1

Your scheme is strange to me. Why start a thread, but have it wait until some unknown time in the future to get told to run? Why not just start it at that later time?

EDIT ADDED to clarify to glowcoder

EDIT REMOVED - My bad, I misunderstood his question, he wants to be able to call MyFunction multiple times. In that case he should use some sort of Queue as suggested in other answers

user949300
  • 15,364
  • 7
  • 35
  • 66
  • Presumably the other operation takes a particular amount of time to complete that would be better spent not blocking the main thread doing. Consider for example reading a feed or socket communication. – corsiKa Dec 20 '11 at 06:46
  • No need to block, you can still run the other operation in another thread. Just don't start it until you are ready. – user949300 Dec 20 '11 at 06:55
  • perhaps not, but then you have to start a new thread each time, or use a thread pool or executor service. Which I'm not entirely opposed to as those are valuable things to learn, but they aren't the scope of the question. – corsiKa Dec 20 '11 at 07:10