这是我的第一篇博客.首先我不会用特别专业的术语来描述,我也不喜欢到处黏来粘去的,我会用最通俗的话来描述,如有错误请指正.
今天突然提到有一个接口的查询特别慢,原因是数据量过大,尝试用多种办法解决,其中一个就是用CountDownLatch类来管理多线程.
用到CountDownLatch首先得了解他2个核心的方法 await();和 countDown();
在开辟多线程的时候首先我们 ;这是啥不重要,你就当是一个计数器,我们初始化了10; 然后子线程开启后,每个线程把该做的做完了就begin.countDown(); 这时候计数器就会减1.
for(int i=0; i<10; i++){
Thread thread = new Thread(new Tmp1(begin,map));
thread.start();
}
连续10个线程每次-1,这个时候计数器的值应该为0,用处就在这
public static void main(String[] args) {
CountDownLatch begin = new CountDownLatch(10);
Map<Object, Object> map = new HashMap<>();
for(int i=0; i<10; i++){
Thread thread = new Thread(new Tmp1(begin,map));
thread.start();
}
try{
System.out.println("the race begin");
begin.await();
System.out.println("the race end");
System.out.println(map.toString());
}catch(Exception e){
e.printStackTrace();
}
}
}
class Tmp1 implements Runnable{
private CountDownLatch begin;
private Map map;
Tmp1(CountDownLatch begin,Map map){
this.begin = begin;
this.map = map;
}
public void run() {
System.out.println(Thread.currentThread().getName() + " arrived !");
map.put(RandomUtil.randomString(3), 213);
System.out.println(new Date());
begin.countDown();
}
我在主线程里,begin.await();这个方法便是第二个要点,"等待". 也就是休眠,主线程休眠直到begin技术的值为0时才会被唤醒,执行接下来的操作.这便达到由主线程来控制要求所有子线程全部执行完才继续操作,以免造成子线程效果未达到主线程继续操作.
如果你有注意到我主线程有一句System.out.println("the race begin"); 按照现在的程式执行下去,我没办法100%达到第一句话输出"the race begin",有时候主线程需要先执行某些方法然后再才能执行子线程的方法的时候怎么办了(当然我没想到有什么需求,但是我现在就想先输出the race begin),这个时候就需要另一个计数器来控制,所以说叫门闩.
public static void main(String[] args) {
CountDownLatch begin = new CountDownLatch(10);
CountDownLatch end = new CountDownLatch(1);
Map<Object, Object> map = new HashMap<>();
for(int i=0; i<10; i++){
Thread thread = new Thread(new Tmp(begin,end,map));
thread.start();
}
try{
System.out.println("the race begin");
end.countDown();
end.await();
begin.await();
System.out.println("the race end");
System.out.println(map.toString());
}catch(Exception e){
e.printStackTrace();
}
}
}
class Tmp implements Runnable{
private CountDownLatch begin;
private CountDownLatch end;
private Map map;
Tmp(CountDownLatch begin,CountDownLatch end,Map map){
this.begin = begin;
this.end = end;
this.map = map;
}
public void run() {
try{
end.await();
System.out.println(Thread.currentThread().getName() + " arrived !");
map.put(RandomUtil.randomString(3), 213);
System.out.println(new Date());
begin.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
以上便是改进的,利用第二个计数器,计数为1,开辟10个子线程后,每个子线程因为end被迫休眠,就在那等,等到主线程减1后,大家一起被唤醒,end.await()应该是多余的,大家一起被唤醒执行,这个时候我执行了begin.await();主线程又被休眠了,子线程挨个减1,直到begin为0时候,继续输出.这个就完成了控制首尾正常输入,内部子线程在那自己去抢着玩的效果;
----我的代码里同时还实现了一个赛跑的场景,如果从效率来讲以上代码并不是最快的,因为每个子线程被迫等待,就像赛跑,每个比赛人员已经准备好了,但是没有开始就不能跑,子线程就在那等主线程的信号,如果我们把每个子线程的门闩拆掉,在子线程start后不用休眠直接执行,时间上应该是可以提升的.
最后,我发布出来只是作为我自己的一个日志记录,理性讨论或者指导,我非常欢迎
我可不是什么岁月静好的男网友,如果你要喷我,我绝对会骂你然后拉黑.逢年过节诅咒你