多執行緒併發篇——三件兵器

追風少年10發表於2018-11-27
display: block;
padding: 15px 15px 15px 1rem;
font-size: 0.9em;
margin: 1em 0px;
color: rgb(0, 0, 0);
border-left: 5px solid rgb(239, 112, 96);
background: rgb(239, 235, 233);
overflow: auto;
overflow-wrap: normal;
word-break: normal;
“>

color: inherit;
line-height: inherit;
padding: 0px;
margin: 1.7em 0px;
“>talk is cheap,show me the code
color: inherit;
line-height: inherit;
padding: 0px;
margin: 0px;
“>JUC其實是屬於執行緒知識的中高階部分,所以也是面試中面試官喜歡問的一塊知識點,這塊知識也能比較看出一個程式設計師的功底,今天筆者就跟大家講講CountDownLatch,CyclicBarrier,Semaphore這些知識點。大家在看到這些知識的時候,千萬不要一上來就摳細節,首先應該弄明白這些知識點時是幹什麼用的,用來解決什麼問題,適合應用於什麼樣的業務場景。如果這些東西都沒搞清楚就學,那麼你學完很快就會忘掉。

line-height: inherit;
margin: 0px;
display: inline-block;
font-weight: normal;
background: rgb(239, 112, 96);
color: rgb(255, 255, 255);
padding: 3px 10px 1px;
border-top-right-radius: 3px;
border-top-left-radius: 3px;
margin-right: 3px;
“>閉鎖CountDownLatch display: block;
padding: 15px 15px 15px 1rem;
font-size: 0.9em;
margin: 1em 0px;
color: rgb(0, 0, 0);
border-left: 5px solid rgb(239, 112, 96);
background: rgb(239, 235, 233);
overflow: auto;
overflow-wrap: normal;
word-break: normal;
“>

color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
"> 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
}
複製程式碼

color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“>執行結果
 1裁判員哨聲響起..
21號選手準備就緒,等待裁判員哨聲響起..
32號選手準備就緒,等待裁判員哨聲響起..
43號選手準備就緒,等待裁判員哨聲響起..
54號選手準備就緒,等待裁判員哨聲響起..
65號選手準備就緒,等待裁判員哨聲響起..
73號選手到達終點..
81號選手到達終點..
94號選手到達終點..
105號選手到達終點..
112號選手到達終點..
12所有運動員到達終點,耗時:17708083042
13
14Process 
finished 
with 
exit 
code 
0
複製程式碼

color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“>CountDownLatch實時系統中的使用場景
    color: inherit;
    line-height: inherit;
    margin: 0px;
    padding: 0px;
    margin-bottom: 0.5em;
    “> color: inherit;
    line-height: inherit;
    margin: 0px;
    padding: 0px;
    margin-bottom: 0.5em;
    “> color: inherit;
    line-height: inherit;
    margin: 0px;
    padding: 0px;
    margin-bottom: 0.5em;
    “> line-height: inherit;
    margin: 0px;
    display: inline-block;
    font-weight: normal;
    background: rgb(239, 112, 96);
    color: rgb(255, 255, 255);
    padding: 3px 10px 1px;
    border-top-right-radius: 3px;
    border-top-left-radius: 3px;
    margin-right: 3px;
    “>迴圈屏障CyclicBarrier display: block;
    padding: 15px 15px 15px 1rem;
    font-size: 0.9em;
    margin: 1em 0px;
    color: rgb(0, 0, 0);
    border-left: 5px solid rgb(239, 112, 96);
    background: rgb(239, 235, 233);
    overflow: auto;
    overflow-wrap: normal;
    word-break: normal;
    “>

    color: inherit;
    line-height: inherit;
    padding: 0px;
    margin: 1.7em 0px;
    “>  需求:人們(執行緒)先後到達餐桌上(某個點),但是不能動筷子(等待),所有人到齊才可以吃年夜飯(執行緒到齊才能一同執行)
     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 


    0;
     

    <
     
    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
    }
    複製程式碼
    color: inherit;
    line-height: inherit;
    margin: 0px;
    padding: 0px;
    “>執行結果
     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
    複製程式碼

    line-height: inherit;
    margin: 0px;
    display: inline-block;
    font-weight: normal;
    background: rgb(239, 112, 96);
    color: rgb(255, 255, 255);
    padding: 3px 10px 1px;
    border-top-right-radius: 3px;
    border-top-left-radius: 3px;
    margin-right: 3px;
    “>區別 color: inherit;
    line-height: inherit;
    margin: 0px;
    padding: 0px;
    padding-left: 32px;
    list-style-type: disc;
    “>
  • color: inherit;
    line-height: inherit;
    margin: 0px;
    padding: 0px;
    “>CountDownLatch減計數,CyclicBarrier加計數。
  • color: inherit;
    line-height: inherit;
    margin: 0px;
    padding: 0px;
    “>CountDownLatch是一次性的,CyclicBarrier可以重用。

    line-height: inherit;
    margin: 0px;
    display: inline-block;
    font-weight: normal;
    background: rgb(239, 112, 96);
    color: rgb(255, 255, 255);
    padding: 3px 10px 1px;
    border-top-right-radius: 3px;
    border-top-left-radius: 3px;
    margin-right: 3px;
    “>訊號量Semaphore display: block;
    padding: 15px 15px 15px 1rem;
    font-size: 0.9em;
    margin: 1em 0px;
    color: rgb(0, 0, 0);
    border-left: 5px solid rgb(239, 112, 96);
    background: rgb(239, 235, 233);
    overflow: auto;
    overflow-wrap: normal;
    word-break: normal;
    “>

    color: inherit;
    line-height: inherit;
    padding: 0px;
    margin: 1.7em 0px;
    “>  需求:假如現在網咖有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 


    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
    }
    複製程式碼
    color: inherit;
    line-height: inherit;
    margin: 0px;
    padding: 0px;
    “>執行結果
     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
    複製程式碼

    https://juejin.im/post/5bfcb99cf265da613e21edd5

  • 相關文章