Java等待线程终止,用于加载数据再刷新界面等操作
最近一直在进行android应用的开发,当时做的app有这样一个需求,即先从网络上加载资源,然后再将资源放入adapter中进行展示。为了实现这种需求,我们必须等待数据加载线程的终止,然后再调用UI线程来对数据进行展示。在android开发中,或者说在java开发中,我们可以使用Thread类中的join()方法来实现这个需求,废话不多说,直接上代码。
首先,我们需要两个线程类,一个线程进行数据加载,一个进行网络连接,在本博客中,未对线程中的具体数据加载和网络连接操作进行实现,仅进行了模拟。
(1)进行数据加载操作的线程类
public class DataSourceLoader implements Runnable{
@Override
public void run()
{
//可以在此处加载数据,此处省略数据加载操作
System.out.println("Begin to load source:"+new Date());
try {
//线程睡眠4秒
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
// 对线程的操作在抛出异常时,一般使用InterruptedException
e.printStackTrace();
}
System.out.println("Data source load finished:"+new Date());
}
}
在DataSourceLoader中,没有对数据进行加载的实际操作,而是让该线程睡眠了4秒,然后打印了其开始和结束时间,以此来让我们在结果中明确的看到线程之间的执行顺序。
此线程类的定义继承了Runnable接口,要定义线程类,还可以通过继承Thread类来进行实现,此线程类的Thread实现方式如下所示:
public class DataSourceLoader extends Thread
{
@Override
public void run()
{
//可以在此处加载数据,此处省略数据加载操作
System.out.println("Begin to load source:"+new Date());
try {
//线程睡眠4秒
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
// 对线程的操作在抛出异常时,一般使用InterruptedException
e.printStackTrace();
}
System.out.println("Data source load finished:"+new Date());
}
}
这两种方法的差别并不大,只是在定义对象时略微有一点差别,差别将在后述内容中展示。
(2) NetworkConnectionLoader类
在该线程类中,可以实现网络的连接,其代码如下:
public class NetworkConnectionLoader implements Runnable{
@Override
public void run()
{
//可以在此处模拟网络连接操作,此处省略
System.out.println("Begin network connection:"+new Date());
try {
//线程睡眠6秒
TimeUnit.SECONDS.sleep(6);
} catch (InterruptedException e) {
// 对线程的操作在抛出异常时,一般使用InterruptedException
e.printStackTrace();
}
System.out.println("Network Connecion finished:"+new Date());
}
}
此处没有实现具体的网络连接操作,仅让线程休眠了6秒,并打印了开始与结束时间。
(3)在主方法中对这两个线程进行调用
本方法完成了在主线程对上述两个数据相关操作线程类的对象实现及调用,其代码如下:
public static void main(String[] args) {
//在主线程中新建两个线程
DataSourceLoader dsLoader = new DataSourceLoader();
Thread thread1 = new Thread(dsLoader,"DataSourceLoaderThread");
NetworkConnectionLoader ncLoader = new NetworkConnectionLoader();
Thread thread2 = new Thread(ncLoader,"NetworkConnectionLoader");
thread1.start();
thread2.start();
//关键操作,对线程执行join操作,使得调用这两个线程的线程需等待这两个线程执行完成才能够继续执行
//join()方法将会抛出InterruptedException
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
// 排除InterruptedException
e.printStackTrace();
}
System.out.println("Main finished,data has been loaded:"+new Date());
}
其执行结果如下图所示:
从结果中可以看出,通过在主方法中调用这两个线程,并对这两个线程执行join操作,可以发现主线程在等待两个被调用线程执行完之后再继续执行。
如果注释掉join()方法,其执行结果如下:
从执行结果来看,主线程并未等待两个数据线程执行结束便已经执行,如果这样,在应用中的数据便不能加载成功。
文章的最后,介绍一下通过Runnable接口和继承Thread类来实现线程类在对象定义上的区别。
下属代码是通过Runnable接口实现的线程类的对象定义方法
DataSourceLoader dsLoader = new DataSourceLoader();
Thread thread1 = new Thread(dsLoader,"DataSourceLoaderThread");
与之相比,通过Thread类定义的线程类会更加简便一些,仅需下述一行即可
DataSourceLoader thread1 = new ThreadSourceLoader();
对了,切记一个线程要执行必须要对其进行start()操作,否则它是不会跑起来的。