Многопоточные параллелизм статей — три оружия

Java задняя часть программист опрос

Автор - java-программист из Гуанчжоу. Я только что закончил полгода назад. В свободное время пишу блог. Если вы считаете, что мои статьи хорошо написаны, вы можете подписаться на мой публичный аккаунт WeChat (J2 Binbin), там будет более захватывающий контент. Я начал вести блог в августе 2018 года и надеюсь написать больше простых для понимания технических статей, чтобы поделиться ими с вами в будущем.

talk is cheap,show me the code

JUC на самом деле относится к промежуточной и продвинутой части знаний о потоках, поэтому это также точка знаний, которую интервьюеры любят спрашивать в интервью.Эти знания также могут сравнивать навыки программиста.Сегодня я расскажу вам о CountDownLatch, CyclicBarrier, Semaphore эти очки знаний. Когда эти знания увидят все, не вникайте в детали, как только они всплывут, в первую очередь нужно понять, для чего нужны эти очки знаний, для решения каких задач они используются и для каких бизнес-сценариев подходят заявление. Если вы изучаете эти вещи, не понимая их, вы вскоре забудете их после изучения.

   Автор и ранее выкладывал некоторые знания о JUC, но это тоже какой-то демо-код, и я подробно его не изучал.Сегодня я поведу вас: войдите в логово тигра и получите сына тигра.

Защелка

Если вы сравните несколько потоков со спортсменами, 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

  • Достижение максимального параллелизма. Иногда нам нужно запустить несколько потоков одновременно, чтобы добиться максимального параллелизма. Например, мы хотим протестировать одноэлементный класс. Если мы создадим CountDownLatch с начальным счетчиком, равным 1, и позволим всем остальным потокам ждать этой блокировки, нам нужно будет вызвать метод countDown() только один раз, чтобы позволить всем другим ожидающим потокам возобновить выполнение в то же время.
  • Подождите, пока N потоков завершат свои задачи, прежде чем начать выполнение: например, класс запуска приложения гарантирует, что все N внешних систем запущены и работают, прежде чем обрабатывать запросы пользователей.
  • Обнаружение взаимоблокировки. Очень удобный случай использования — это когда вы используете N потоков для доступа к общему ресурсу с разным количеством потоков на каждой фазе тестирования и пытаетесь создать взаимоблокировку.

циклическийбарьер

CyclicBarrier очень похож на CountDownLatch, но есть некоторые отличия. Давайте сначала посмотрим на код.

  Требования: Люди (нити) подходят к столу (определенная точка) друг за другом, но не могут двигать палочками (ожидание), и все могут устроить новогодний ужин, когда они придут (нити можно выполнять вместе)

 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 можно использовать повторно.

семафор

Семафор похож на блокировку, но в отличие от блокировки синхронизация является эксклюзивной, только один поток может одновременно управлять ресурсом, в то время как семафор позволяет нескольким потокам работать с одним и тем же ресурсом в одно и то же время. Он управляет несколькими потоками для управления ресурсами, получая разрешение и освобождая разрешение.

Требование: Допустим, в интернет-кафе 5 компьютеров, но сейчас в интернет-кафе заходят 8 человек, одновременно могут попасть в компьютер только 5 человек, а 3 из них могут попасть в компьютер только тогда, когда другие люди освободили свои компьютеры.
Вот где 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, поэтому автор продолжит публиковать соответствующие статьи в блоге в будущем. и я надеюсь, что читатели будут терпеливы.