需求
解析一个Excel中多个sheet的数据,那么此时就可以考虑使用多线程,每个线程解析一个sheet中的数据,然后等待所有的sheet数据解析完成后,再把数据入库
在这个需求中,要实现主线程等待所有现场完成shee数据解析操作,
第一种方案:采用join()方法
public class MyJoinTest {
public static void main(String[] args) throws InterruptedException {
System.out.println("开始解析数据");
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("解析sheet1 的数据");
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("解析sheet2 的数据");
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("入库");
System.out.println("完成");
}
}
执行结果:
看一下Thread的join方法
public final void join() throws InterruptedException {
join(0);
}
死循环检查join线程是否活着,如果join线程活着则让当前线程永远等待,其中wait(0);表示永远等下去。直到join线程终止后,线程的this,notifyAll()方法会被调用,调用this.notifyAll方法是在JVM里面实现的。只有再JVM源码里能看见。
在JDK1.5后的并发包下提供了CountDownLatch也可以实现join的功能,并且比join的功能更多,
第二种方案:CountDownLatch
代码如下:
public class MyCountDownLatch {
static CountDownLatch count = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("解析sheet1 的数据");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count.countDown();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("解析sheet2 的数据");
count.countDown();
}
}).start();
count.await();
System.out.println("入库");
System.out.println("完成");
}
}
执行结果
CountDownLatch的构造函数接收一个Int类型的参数作为计数器,如果你想等待n个点完菜,这里就传n。
当我们调用CountDownLatch的countDown()方法时候n就减1即就是n=n-1。CountDownLatch的await方法会阻塞当前线程,知道n=0,由于countDown()方法可以再任何地方使用,所以这里的n个点,可以是n个线程,也可以是一个线程里的n个执行步骤。用在多线程时,只需要把这个CountDownLatch的引用传递到线程里即可。
注:
计数器必须大于0,计数器等于0的时候,调用await方法是不会阻塞当前线程,CountDownLatch不可能重新初始化或者修改CountDownLatch对象的内部计数器的值,一个线程调用countDown方法happen-before,另外已发个线程调用await方法。
参考:《Java并发编程的艺术》