多线程并发篇——三件兵器

  笔者是广州的java程序员,刚毕业半年,工做之余写博客,若是以为个人文章写得不错,能够关注个人微信公众号(J2彬彬),里面会有更多精彩内容。从2018年8月份开始写博客,但愿往后写出更多通俗易懂的技术文章与你们一同分享。java

talk is cheap,show me the code程序员

JUC实际上是属于线程知识的中高级部分,因此也是面试中面试官喜欢问的一块知识点,这块知识也能比较看出一个程序员的功底,今天笔者就跟你们讲讲CountDownLatch,CyclicBarrier,Semaphore这些知识点。你们在看到这些知识的时候,千万不要一上来就抠细节,首先应该弄明白这些知识点时是干什么用的,用来解决什么问题,适合应用于什么样的业务场景。若是这些东西都没搞清楚就学,那么你学完很快就会忘掉。面试

  以前笔者也发过一些关于JUC方面的知识,但也就是一些Demo代码,并无细究,今天就是带领你们:入虎穴,得虎子。微信

闭锁CountDownLatch

若是把多个线程比喻成运动员,CountDownLatch至关于枪声发令员,枪声未响,全部线程都处于等待状态,当CountDownLatch计数器变为0时
至关于枪声发出,这时全部线程一同奔跑。与集齐七颗龙珠即可召唤神龙有殊途同归之妙。多线程

 1package com.bingo.thread.juc;
2
3/**
4 * Created with IntelliJ IDEA.
5 * Description: 倒时计数器(也叫闭锁)
6 * User: bingo
7 * Date: 2018-11-25
8 * Time: 11:16
9 */

10import java.util.concurrent.CountDownLatch;
11import java.util.concurrent.ExecutorService;
12import java.util.concurrent.Executors;
13
14public class CountDownLatchDemo {
15
16    public static void main(String[]args) throws InterruptedException{
17        final CountDownLatch startGate=new CountDownLatch(1);
18        final CountDownLatch endGate=new CountDownLatch(5);
19        //线程池
20        ExecutorService exce=Executors.newCachedThreadPool();
21        //建立5个线程
22        for(int i=1;i<=5;i++){
23            final int num=i;
24            Thread thread =new Thread(new Runnable() {
25                public void run() {
26                    try {
27                        System.out.println(num+"号选手准备就绪,等待裁判员哨声响起..");
28                        //至关于同步锁Synchronized中的await()方法
29                            startGate.await();
30                        try {
31                            Thread.sleep((long) (Math.random()*10000));
32                        } catch (InterruptedException e) {
33                            e.printStackTrace();
34                        }
35                        System.out.println(num+"号选手到达终点..");
36                    } catch (InterruptedException e) {
37                        e.printStackTrace();
38                    }
39                    finally{
40                        //至关于同步锁Synchronized中的notify()方法,区别在于countDown须要执行5次后才能唤醒await()
41                        endGate.countDown();
42                    }
43                }
44            });
45            exce.execute(thread);
46        }
47        long start=System.nanoTime();
48        System.out.println("裁判员哨声响起..");
49        Thread.sleep(10000);
50        //唤醒执行startGate.await()的线程,让线程往下执行
51        startGate.countDown();
52        //等待被唤醒,主程序才能继续往下执行,线程中每次执行endGate.countDown()就减1,当为零的时候,主程序往下执行
53        endGate.await();
54        long end=System.nanoTime();
55        System.out.println("全部运动员到达终点,耗时:"+(end-start));
56        //关闭线程池
57        exce.shutdown();
58    }
59}
复制代码
运行结果
 1裁判员哨声响起..
21号选手准备就绪,等待裁判员哨声响起..
32号选手准备就绪,等待裁判员哨声响起..
43号选手准备就绪,等待裁判员哨声响起..
54号选手准备就绪,等待裁判员哨声响起..
65号选手准备就绪,等待裁判员哨声响起..
73号选手到达终点..
81号选手到达终点..
94号选手到达终点..
105号选手到达终点..
112号选手到达终点..
12全部运动员到达终点,耗时:17708083042
13
14Process finished with exit code 0
复制代码

CountDownLatch实时系统中的使用场景

  • 实现最大的并行性:有时咱们想同时启动多个线程,实现最大程度的并行性。例如,咱们想测试一个单例类。若是咱们建立一个初始计数器为1的CountDownLatch,并让其余全部线程都在这个锁上等待,只须要调用一次countDown()方法就可让其余全部等待的线程同时恢复执行。
  • 开始执行前等待N个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,全部N个外部系统都已经启动和运行了。
  • 死锁检测:一个很是方便的使用场景是你用N个线程去访问共享资源,在每一个测试阶段线程数量不一样,并尝试产生死锁。

循环屏障CyclicBarrier

CyclicBarrier与CountDownLatch很是类似,可是仍是有必定区别。咱们先看代码。app

  需求:人们(线程)前后到达餐桌上(某个点),可是不能动筷子(等待),全部人到齐才能够吃年夜饭(线程到齐才能一同执行)dom

 1package com.bingo.thread.juc;
2
3import java.util.concurrent.BrokenBarrierException;
4import java.util.concurrent.CyclicBarrier;
5
6public class CyclicBarrierDemo {
7
8   public static void main(String[] args) {
9      final int count = 5;
10      final CyclicBarrier barrier = new CyclicBarrier(count, new Runnable() {
11         @Override
12         public void run() {
13            System.out.println("人到齐,你们一块儿吃年夜饭!");
14         }
15      });
16
17      // they do not have to start at the same time...
18      for (int i = 0; i < count; i++) {
19         new Thread(new Worker(i, barrier)).start();
20      }
21   }
22}
23
24class Worker implements Runnable {
25   final int id;
26   final CyclicBarrier barrier;
27
28   public Worker(final int id, final CyclicBarrier barrier) {
29      this.id = id;
30      this.barrier = barrier;
31   }
32
33   @Override
34   public void run() {
35      try {
36         System.out.println(this.id + "starts to run !");
37         Thread.sleep((long) (Math.random() * 10000));
38         System.out.println(this.id + "到桌 !");
39         this.barrier.await();
40      } catch (InterruptedException e) {
41         e.printStackTrace();
42      } catch (BrokenBarrierException e) {
43         e.printStackTrace();
44      }
45   }
46}
复制代码
运行结果
 10starts to run !
22starts to run !
31starts to run !
43starts to run !
54starts to run !
64到桌 !
73到桌 !
81到桌 !
92到桌 !
100到桌 !
11人到齐,你们一块儿吃年夜饭!
12
13Process finished with exit code 0
复制代码

区别

  • CountDownLatch减计数,CyclicBarrier加计数。
  • CountDownLatch是一次性的,CyclicBarrier能够重用。

信号量Semaphore

Semaphore与锁相似,可是与锁不一样的是,Synchronized是独占式的,同一时刻只有一个线程可以操做资源,而Semaphore容许指定的多个线程同时操做同个资源。它经过获取许可,释放许可来控制多个线程操做资源。ide

  需求:假如如今网吧有5台电脑,可是如今有8我的进入网吧,同一时间只能有5我的上机,而其中三我的主要等到其余人空出电脑的时候才能上机。
这时Semaphore就派上用场了。学习

 1package com.bingo.thread.juc;
2
3import java.util.concurrent.Semaphore;
4
5public class SemaphoreDemo {
6    public static void main(String[] args) {
7        int N = 8//学生数
8        Semaphore semaphore = new Semaphore(5); //电脑数目
9        for(int i=0;i<N;i++)
10            new Worker(i,semaphore).start();
11    }
12
13    static class Worker extends Thread{
14        private int num;
15        private Semaphore semaphore;
16        public Worker(int num,Semaphore semaphore){
17            this.num = num;
18            this.semaphore = semaphore;
19        }
20
21        @Override
22        public void run() {
23            try {
24                semaphore.acquire();
25                System.out.println("同窗"+this.num+"占用一台电脑...");
26                Thread.sleep(2000);
27                System.out.println("--同窗"+this.num+"离开电脑");
28                semaphore.release();           
29            } catch (InterruptedException e) {
30                e.printStackTrace();
31            }
32        }
33    }
34}
复制代码
运行结果
 1同窗0占用一台电脑...
2同窗1占用一台电脑...
3同窗2占用一台电脑...
4同窗3占用一台电脑...
5同窗4占用一台电脑...
6--同窗0离开电脑
7--同窗1离开电脑
8--同窗4离开电脑
9--同窗3离开电脑
10同窗7占用一台电脑...
11--同窗2离开电脑
12同窗6占用一台电脑...
13同窗5占用一台电脑...
14--同窗7离开电脑
15--同窗5离开电脑
16--同窗6离开电脑
17
18Process finished with exit code 0
复制代码

  多线程是java面试中很是重要一环,算是重点和难点吧,特别是须要结合JVM一块儿学习,因此从此笔者还会继续推出相关博客文章,也但愿读者耐心等待。测试

相关文章
相关标签/搜索