万丈高楼平地起,要精通也要一步步开始。先来学习concurrent包下的CountDownLatch这个类。
1.为什么先学这个类?
答:实用。我觉得这个类在实际的项目中是很有用的。
下面提出几个实际开发中经常遇到的问题,当然这些问题的解决方案是很多的,这里主要还是为了讲解CountDownLatch类的使用。可能存在更好的解决方案,但这里只提供CountDownLatch这种解决方案。
需求1:在GUI应用中插入一些数据的到数据库中,如获取高德地图的城市json数据并且保存到数据库中,点击三级联动控件显示省、县数据。
存在问题:不知道插入数据存在什么时候完成,提前点击三级联动控件可能导致城市数据显示不全。
解决思路:如果我们能够知道什么时候完成了数据库插入操作。
需求2:完善资料页面,app中这种需求很常见。要求用户上传头像,输入昵称,性别等信息。当网络环境不好时,头像还没上传完成,用户点击提交按钮,将会出现问题。
存在问题:提交按钮的时候判断返回的服务器地址是否为空,如果为空则提示“请上传头像”。但是过来一会上传完成地址不为空了。
解决思路:如果知道什么时候完成头像上传,上传的过程点提交则提示"头像正在上传中"。
2.怎么使用CountDownLatch?
先说说这个CountDownLatch是个什么东西?字面翻译意思就是倒计时门闩,用一句话说完,这个类能在线程执行完的时候进行减一计数,当计数减到零时,计数结束,打开门闩,执行后面的代码。
举个栗子:计算10个线程的总执行时间
/**
* Created by Perk on 2018/12/18.
*/
public class CountDownLatchDemo {
public static void main(String[] args) {
CountDownLatchDemo demo = new CountDownLatchDemo();
demo.countRunTime();
}
/**
* 计数多线程总运行时间
*/
public void countRunTime() {
CountDownLatch cdt = new CountDownLatch(10);//设置计数器数量为10
//开始时间
long start = System.currentTimeMillis();
//开启10个线程
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new MyThread(cdt));
thread.start();
}
//在十个线程完成之前阻止向下执行
try {
//这行代码后面的代码只有当CountDownLatch的计数为0时才会执行,
// 就想一个闸门,挡住去路,也是CountDownLatch的英文的字面意思
cdt.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//十个线程都完成之后执行
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) + "ms");
}
class MyThread implements Runnable {
CountDownLatch countDownLatch;
public MyThread(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
synchronized (this) {
for (int i = 0; i < 10000; i++) {
System.out.println(i);
}
}
} finally {
//执行完一个线程计数减1
countDownLatch.countDown();//CountDownLatch的核心倒计数功能
}
}
}
}
每完成一个线程,CountDownLatch调用countDown()方法计数减1。