我有一个主线程和一个并行运行的线程,我希望能够先运行该线程,然后再移至其他任何线程,例如我的主线程。
我试图查看Google,但是找不到答案。
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");
}
就像我在上面说的那样,我希望我的线程完成并进入X睡眠时间,例如24小时,然后在进入睡眠状态时移回我的主线程。
目标是建立一个首先更新所有客户帐户的银行系统,然后运行的方法(我的第二个线程)将在接下来的24小时内进入睡眠状态。然后移回我的主体。
答案 0 :(得分:1)
您在上面的代码中所做的操作创建了一个与主线程同时运行的线程。实际发生的是:
Main
线程甚至可能在AutoUpdater线程真正启动之前终止。因此,坚持使用现有的内容,第一步是使AutoUpdater线程每24小时运行一次。可以执行此操作的一种方法是保持线程运行,并在run方法中放置一个while循环,这样它不会终止,而是每24小时处理一次clients
集合。所以现在AutoUpdater
可能看起来像这样:
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.");
}
}
}
}
但是,上面的代码存在一些问题,因为它会漂移。例如,如果处理需要一个小时,那么下一次运行将是在上次运行初始开始后25小时。幸运的是,Java提供了一个线程执行程序服务,该服务将按照固定的时间表ScheduledExecutorService
运行线程。因此,让我们放松while
循环并引入执行程序。
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");
}
}
现在,自启动进程以来,我们每24小时运行一次自动更新程序线程。如果您想确定时间,例如每天8点,您可以计算到该时间的延迟(尽管这不会考虑夏时制问题),也可以使用Quartz这样的第三方库来安排特定时间一天中的时间。
我希望能够先运行该线程,然后再移至其他任何线程,例如我的主线程。
大概是这样,您的意思是要在自动更新运行时停止其他线程的执行。为此,您有几个可用的选项。在第一种情况下,您可以使用监视器来同步和锁定线程,即
Object sharedMonitor = new byte[0]
// In your auto-updater and other threads
synchronised(sharedMonitor ) {
}
以上语法仅允许单个线程一次为同一监视器实例输入synchronized
块。在上面只有两个线程的示例中,这可以很好地工作。如果您拥有两个以上的线程,那么它将成为问题,因为您只希望在自动更新程序运行时阻塞其他线程。在这种情况下,这不是适合您的解决方案。您所要做的就是让所有线程同时运行,直到需要运行自动更新程序,然后它们都需要阻塞并等待自动更新程序完成。对您来说幸运的是,Java有一个ReadWriteLock
可以做到这一点。
因此,我们添加该锁并使用它。
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();
}
}
}
}
所以上面有:
while
循环中,我们从一开始就获得了读取锁定,并在结束时释放了读取锁定。 难题的最后一步是使用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();
}
}
}