Reputation:
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
Reputation: 886
What you have done in your code above created a thread that runs concurrently with the main thread. What actually happens is:
Main
thread may even terminate before the AutoUpdater thread has really started.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:
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