user9182294
user9182294

Reputation:

Move to main thread after another thread go to sleep

I have my main and a thread running alongside it, I want to be able to run the thread first and then move to any other thread, for example, my main.

I tried to look over google but could not find an answer.

public class AutoUpdater implements Runnable {
    public void run() {
        System.out.println("Thread is running...");
        for (int i = 0; i < clients.size(); i++) {
            do something...
        }
        System.out.println("Thread ended.\n");
        int time = 1000 * 60 * 60 * 24;
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            System.out.println("Something interrputed thread while running.");
        }
    }

public class Main {
            public static void main(String[] args) throws IOException, ClassNotFoundException {

                Runnable runnable = new AutoUpdater(clients);
                Thread thread = new Thread(runnable);
                thread.start();
                        // run after the above thread finish and go to sleep
                System.out.println("This is a test");
            }

Like I said above I want my thread to finish and go sleep for X time, for example, 24 hours and when it goes to sleep move back to my main thread.

The goal is to make a bank system that updates all clients accounts first and then the method run (my second Thread) will go sleep for the next 24 hours. and move back my main.

Upvotes: 0

Views: 619

Answers (1)

Marc G. Smith
Marc G. Smith

Reputation: 886

What you have done in your code above created a thread that runs concurrently with the main thread. What actually happens is:

  1. Main thread starts and initiates AutoUpdater thread
  2. The two threads will run concurrently. In fact, the Main thread may even terminate before the AutoUpdater thread has really started.
  3. The auto-update thread processes the clients ONCE, then sleeps for 24 hours and then terminates and your program completely terminates at this point.

So sticking with what you have, the first step is to get the AutoUpdater thread to run every 24 hours. One way you could do this is to keep the thread running and put a while loop in the run method so that it doesn't terminate but processes the clients collection every 24 hours. So now AutoUpdater might look like this:

public class AutoUpdater implements Runnable {
    public void run() {
        while (true) {
            try {
                System.out.println("Thread is running...");
                for (int i = 0; i < clients.size(); i++) {
                    // do something...
                }
            } finally {
                System.out.println("Thread ended.\n");
            }

            int time = 1000 * 60 * 60 * 24;
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                System.out.println("Something interrputed thread while running.");
            }
        }
    }
}

However, the code above has some issues in that it will drift. If for example, processing takes an hour then the next time it runs will be 25 hours after the last run initial started. Fortunately, Java provides a thread executor service that will run your thread on a fixed schedule called ScheduledExecutorService. So let's unwind the while loop and introduce the executor instead.

public class AutoUpdater implements Runnable {
    public void run() {
        System.out.println("Thread is running...");
        for (int i = 0; i < clients.size(); i++) {
            // do something...
        }
        System.out.println("Thread ended.\n");
    }
}

public static class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        executor.scheduleAtFixedRate(
                    new AutoUpdater(clients, lock.writeLock()),
                    0,
                    24,
                    TimeUnit.HOURS);

        System.out.println("This is a test");
    }
}

Now we've got the auto-updater thread running every 24 hours from when we started the process. If you want to fix the time, i.e. at 8 AM every day you can either calculate the delay till that time (though this won't take into account daylight saving issues) or use a third-party library like Quartz to schedule at a specific time of day.

I want to be able to run the thread first and then move to any other thread, for example, my main.

Presumably by this, you mean that you want to stop other threads from executing while the Auto-Update is running. For this, you have several options available. In the first instance, you can use a monitor to synchronize and lock threads, i.e.

Object sharedMonitor = new byte[0]

// In your auto-updater and other threads
synchronised(sharedMonitor ) {

}

The syntax above will only allow a single thread to enter a synchronized block at a time for the same monitor instance. This would work fine in the example above where you only have the two threads. If you have more than the two threads it becomes problematic as you only really want the other threads to block when the auto-updater is running. In this case, this isn't the right solution for you. What you are after is something that will let all the threads run concurrently until the auto-updater needs to run and then they all need to block and wait for the auto-updater to finish. Fortunately for you, Java has a ReadWriteLock which does exactly that.

So let's add that lock and use it.

public static class Main {
    private static List<String> clients = new ArrayList<>();

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ReadWriteLock lock = new ReentrantReadWriteLock();

        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        executor.scheduleAtFixedRate(
                new AutoUpdater(clients, lock.writeLock()),
                0,
                24,
                TimeUnit.HOURS);

        Lock readLock = lock.readLock();
        while (true) {
            try {
                readLock.lock();
                System.out.println("This is a test");
            } finally {
                readLock.unlock();
            }
        }
    }
}

So above we have:

  1. Added a read-write lock
  2. Passed the write lock to AutoUpdater
  3. Added a while loop to the main method so it doesn't terminate and can do whatever run-of-the-mill processing it is meant to be doing.
  4. In the while loop we've acquired the read lock at the start and released it at the end.

The last piece of the puzzle is to use the write lock in AutoUpdater

public class AutoUpdater implements Runnable {
    public void run() {
        try {
            lock.lock();
            System.out.println("Thread is running...");
                // do something...
            }
        } finally {
            System.out.println("Thread ended.\n");
            lock.unlock();
        }
    }
}

Upvotes: 1

Related Questions