0

I have 2 methods methodA, methodB. They run on different threads. I want methodB to run with a delay of 100 milliseconds after methodA have started, how do I do that?

the code

final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(3);
executor.schedule(() -> highs(), 100, TimeUnit.MILLISECONDS);
new Thread(() -> highs()).start();
new Thread(() -> deleteRecords()).start();

I noticed that despise this, methodB always runs before methodA.

ken4ward
  • 2,246
  • 5
  • 49
  • 89
  • Where are methodA and B? I see `highs()` and `deleteRecords()`. – Matthieu Dec 08 '19 at 05:28
  • Yeah. sorry for the wrong method names. As it is, ```methodA=deleteRecords, methodB =highs()``` – ken4ward Dec 08 '19 at 05:31
  • Is that something you're just experimenting with (then it won't matter), or do you need it in real life? Then the accepted answer has a flaw, it can't guarantee that A will run before B, it just guarantees that B starts with a delay of 100sec after scheduling B. Add more threads, use another machine/processor whatever, and B may overtake A. To be ultimately on the save side you'd need a [semaphore](https://stackoverflow.com/questions/2332765/lock-mutex-semaphore-whats-the-difference/2332868) I think – Curiosa Globunznik Dec 08 '19 at 05:53
  • 1
    Looks like Thread.wait and Thread.notify can guarantee execution of relevant parts of A before B executes, check [this out](https://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example). – Curiosa Globunznik Dec 08 '19 at 06:15

2 Answers2

2

If you want to synchronize processing between threads, you can use wait()/notify(), but if you're not sure about the order in which those "processings" will take place, I suggest you use a Semaphore instead:

Semaphore sem = new Semaphore(0); // Initialize an empty Semaphore
new Thread(() -> { // This is thread A processing, that should run first
    methodA(); // Run processing
    sem.release(); // Indicate processing is finished
}).start();

new Thread(() -> { // This is thread B processing, that should run after methodA() has completed
    sem.acquire(); // Blocks until release() is called by thread A
    methodB(); // Run processing
}).start();

Original answer:

You wrote:

executor.schedule(() -> highs(), 100, TimeUnit.MILLISECONDS);

In 100ms highs() will start.

new Thread(() -> highs()).start();

Another highs() starts right now.

new Thread(() -> deleteRecords()).start();

deleteRecords() starts right now.

So highs() will be run twice: once with new Thread(() -> highs()).start() and then later with executor.schedule().

Just comment out the new Thread(() -> highs()).start() and the first executor schedule will trigger as you expected.

Note that thread execution does not necessarily happen in the order it was called, but it usually is the case though.

Matthieu
  • 2,736
  • 4
  • 57
  • 87
  • Same problem like with the other answer, the approach doesn't guarantee that a could do what it was supposed to do before b. – Curiosa Globunznik Dec 08 '19 at 06:08
  • @gurioso: the question was about starting b after a had *started*, not *completed*. Though of course it all sounds like he wants to recreate a kind of sequentiality with threads, which would be plain wrong if that was the case... – Matthieu Dec 08 '19 at 07:27
  • @Matthieu, you truly spoke my mind. I want the methods to run sequentially. MethodA before MethodB – ken4ward Dec 08 '19 at 12:24
  • @ken4ward then why don't you run both methods in sequence: `methodA(); methodB()`? Is using threads a necessity? In that case you'll have to use synchronization with `wait()` and `notify()`. – Matthieu Dec 08 '19 at 13:23
  • @Matthieu, it's wise instructive advise. Could you provide a code snippet for the implementation as pertaining to my scenario? – ken4ward Dec 08 '19 at 13:51
  • *"...after a had started, not completed"* yes, the initial question was phrased in a misleading way. But why would he insist on a delayed start, if no order is guaranteed anyway? Btw not necesesarily completed, just executed half way through to important point x, only then B must start. – Curiosa Globunznik Dec 08 '19 at 15:03
  • @ken4ward I edited to show a simple synchronization using `Semaphore`. It's a lot cleaner and more efficient than waiting for an arbitrary period of time, as @gurioso noted. – Matthieu Dec 08 '19 at 16:59
1

By having the ThreadPool execute one thread instantly and then schedule one 100ms later, you'll be able to get the effect you are looking for (having 1 thread run methodA and then another thread run methodB 100 milliseconds later). I wrote a small example to test this:

public class Main {

    public static void main (String[] args) {
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(3);
        executor.execute(() -> methodA());
        executor.schedule(() -> methodB(), 100, TimeUnit.MILLISECONDS);
    }

    public static void methodA(){
        System.out.println("A: " + System.currentTimeMillis());
    }

    public static void methodB(){
        System.out.println("B: " + System.currentTimeMillis());
    }
}

This program results in this output:

A: 1575782281388
B: 1575782281492
Curiosa Globunznik
  • 3,129
  • 1
  • 16
  • 24
Stephen
  • 376
  • 1
  • 3
  • 13
  • This is brilliant. Thanks. – ken4ward Dec 08 '19 at 05:35
  • Upvoted for reusing the same executor for all threads. @ken4wards that's almost what you wrote :) – Matthieu Dec 08 '19 at 05:41
  • 2
    The approach guarantees to delay thread b but it doesn't guarantee, that whatever thread a is supposed to do before actually will happen before. See [this post](https://stackoverflow.com/questions/34857910/how-accurate-is-the-task-scheduling-of-a-scheduledthreadpoolexecutor). I'm afraid one would need this awful semaphore stuff to really coordinate the threads. – Curiosa Globunznik Dec 08 '19 at 05:50
  • 1
    Looks like Thread.wait and Thread.notify can guarantee the sequence, demonstrated e.g. [here](https://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example) – Curiosa Globunznik Dec 08 '19 at 06:06