Java中併發工具包 - 上

併發工具概述

體系結構

        A.併發工具處於java.util.concurrent包

        B.其實包括的內容有:
            -同步器
            -執行器
            -併發集合
            -Fork/join框架
            -atomic包
            -locks包

各組成部分和作用

          同步器:爲各種特定的同步問題提供瞭解決方案

          執行器:用來管理線程的執行

        併發集合:提供了集合框架中集合的併發版本

   Fork/Join框架:提供了對併發編程的支持

        atomic包:提供了不需要鎖即可完成併發環境變量使用的原子性操作 

         locks包:使用lock接口爲併發編程提供了同步的另一種替代方案

同步器Semaphore 和 CountDownLatch API介紹和代碼實現

同步器 Semaphore(信號量)

Semaphore - API

這裏寫圖片描述

Semaphpre - 演示代碼

package com.semaphore.demo1;

import java.util.concurrent.Semaphore;

/**
 * 主函數 - 類
 * 
 *演示目標:模擬銀行窗口服務流程
 * 
 * 條件: 1.有兩個服務窗口
 *       2.三名顧客在等待服務
 * 代碼實現
 * */
public class DemoCase {

    public static void main(String[] args) {
         /*
          * 設置兩個信號量 
          * ps:
          *     1.信號量的數量,就是我允許多少個併發線程進入到這個區域
          *     2.信號量的使用 
          *         A.先獲取信號量
          *         B.進行實際操作。
          *         C.操作完成後,釋放信號量
          *     3.併發線程執行順序是不固定的,也就是隨機的
          * */
        Semaphore semaphore = new Semaphore(3);

        Person p1 = new Person(semaphore, "A");
        p1.start(); 

        Person p2 = new Person(semaphore, "B");
        p2.start(); 

        Person p3 = new Person(semaphore, "C");
        p3.start(); 
    }
}

/**
 * 功能 - 類
 * 
 * */

//1.創建一個內部類,繼承Thread類
class Person extends Thread
{
    //2.創建全局變量 Semaphore 
    private Semaphore semaphore;

    //3.創建類的 有參構造方法
    public Person(Semaphore semaphore ,String name) {
        setName(name);
        this.semaphore = semaphore;
    }

    //4.重寫Thread類的run方法
    @Override
    public void run() {
        System.out.println(getName()+" is waiting ..."); //提示消息:等待服務

        try {
            semaphore.acquire(); //獲取 - 信號量

            System.out.println(getName()+" is Servicing...");//提示消息:服務中

            Thread.sleep(1000); //爲了看出效果,休眠一秒

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println(getName()+"is Done!"); //提示消息 :完成

        semaphore.release(); //釋放 - 信號量
    }



}

Semaphpre - 運行結果

這裏寫圖片描述

Semaphpre - 使用總結

Semaphore 同步器運行特性:
    1.可以自定義同時併發的線程數量。
        如:線程數量爲3,但設置信號量爲2,就會先併發執行兩條線程,然後執行第3條線程。
    2.併發執行線程的順序是隨機的,也就是說沒有固定順序。

Semaphore API應用及其運行步驟
    1.功能類 書寫步驟
        1. - semaphore.acquire(); //獲取主函數的數量
        2. - 功能實現部分
        3. - semaphore.release(); //釋放信號量

    2.調用類 書寫步驟  
        1. -Semaphore semaphore = new Semaphore(2);//創建 semaphore 對象實例,設置信號量的數量也就是併發執行的線程數量 
        2.Person p1 = new Person(semaphore, "A");
          p1.start();  //創建功能類對象實例,啓動線程

CountDownLatch(計數栓)

CountDownLatch - API

這裏寫圖片描述

CountDownLatch - 演示代碼

package com.countdownlatch.demo1;

import java.util.concurrent.CountDownLatch;

/**
 * 主函數 - 類
 * 
 * 演示目標:模擬賽跑比賽,裁判員倒數3,2,1之後,所有線程併發執行
 * 
 * 演示代碼
 * */ 
public class DemoCase {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(3); //創建計數栓對象

        new Racer(countDownLatch,"A").start();
        new Racer(countDownLatch,"B").start();
        new Racer(countDownLatch,"C").start();

        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
                System.out.println(3-i);
                if(i ==2 ) //開始起跑
                {
                    System.out.println("開始起跑");
                }
                /*ps:
                 *  1.開始計數: 每隔一秒計數一次,總計3次也就是三秒
                 *  2.線程的執行順序是不固定的,也就是隨機的
                 * */
                countDownLatch.countDown(); 
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 功能 - 類
 * 
 * */

//1.Racer(運動員)類 繼承 Thread類
class Racer extends Thread
{
    //2.創建共有對象
    private CountDownLatch countDownLatch;

    //3.創建類的有參函數
    public Racer(CountDownLatch countDownLatch,String name) {
        setName(name);
        this.countDownLatch = countDownLatch;
    }

    //4.重寫Thread類的run方法
    @Override
    public void run() {
        try {

            countDownLatch.await();// 等待
            for (int i = 0; i < 3; i++) {
                System.out.println(getName()+":  "+i);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 

        super.run();
    }
}

CountDownLatch - 運行結果

這裏寫圖片描述

CountDownLatch - 使用總結

CountDownLatch 同步器運行特性:
    1.可以自定義線程運行的時間
    2.同樣線程的先後執行順序也是無序的,隨機執行。

CountDownLatch API的應用以及書寫方式 
    功能類:完成需求功能即可。
    調用類:CountDownLatch countDownLatch = new CountDownLatch(3);//創建計數栓對象,並設置計數栓的值。
    countDownLatch.countDown(); //countDown()方法負責統計,每觸發一次,就加1。如:計數栓設置的值是3,那麼 countDown()被觸發3次就會執行所有線程。

同步器- CyclicBarrier、Exchanger 和 Phaser API介紹和代碼實現

同步器- CyclicBarrier(關卡)

CyclicBarrier - API

這裏寫圖片描述

CyclicBarrier - 演示代碼

package com.CyclicBarrier.demo1;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/*
 * 演示目標:模擬鬥地主
 * */
public class DemoCase {
    public static void main(String[] args) {
        /*
         * 創建 CyclicBarrier對象、指定線程數量、以及線程都到達後執行的操作
         * */
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3,new Runnable() { 

            @Override
            public void run() {
                System.out.println("開始 遊戲");
            }
        });

        new Player(cyclicBarrier, "A").start();
        new Player(cyclicBarrier, "B").start();
        new Player(cyclicBarrier, "C").start();
    }
}

// 1.類繼承 Thread類
class Player extends Thread
{
    //2.創建共有對象 
    private CyclicBarrier cyclicBarrier ;

    //3.創建類 有參構造函數
    public Player(CyclicBarrier cyclicBarrier,String name) {
        setName(name);
        this.cyclicBarrier = cyclicBarrier;
    }

    //重寫Thread類  run方法
    @Override
    public void run() {
        System.out.println(getName()+" is waiting other palyers ..."); //提示消息,等待其他玩家

        try {
            cyclicBarrier.await();//等待線程

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
    }

}

CyclicBarrier - 運行結果

這裏寫圖片描述

CyclicBarrier - 使用總結

CyclicBarrier 同步器特性
    1.指定線程數量、以及線程都到達後執行的操作

CyclicBarrier API的應用以及書寫方式
    功能類
        1.在功能類書寫功能代碼,功能代碼後添加 
        cyclicBarrier.await();//等待線程
    調用類:
    //指定線程數量,以及開啓一個新的線程,當所有線程都到達且運行後,共同執行的方法
    CyclicBarrier cyclicBarrier = new CyclicBarrier(3,new Runnable() { 
            @Override
            public void run() {
                System.out.println("開始 遊戲");
            }
        });         

同步器 - Exchanger(交換器)

Exchanger - API

這裏寫圖片描述

Exchanger - 演示代碼

package com.exchanger.demo1;

import java.util.concurrent.Exchanger;


/**
 * 演示目標 :兩條線程 交換字符串
 * 
 * */
public class DemoCase {
    public static void main(String[] args) {
        Exchanger<String> ex = new Exchanger<>();

        new B(ex).start();
        new A(ex).start();

    }
}

//1.繼承 Thread 類
class A extends Thread
{
    //2.創建共有對象 
    private Exchanger<String> ex;

    //3.創建類的 有參構造,傳入參數
    public A(Exchanger<String> ex) {
        this.ex = ex;
    }

    //4.重寫run方法
    @Override
    public void run() {
        String str = null ;
        try {
            str = ex.exchange("Hello?"); //準備要交換的數據
            System.out.println("A的數據:"+str);

            str = ex.exchange("A"); //準備要交換的數據
            System.out.println("A的數據:"+str);

            str = ex.exchange("B"); //準備要交換的數據
            System.out.println("A的數據:"+str);

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
//1.繼承 Thread 類
class B extends Thread
{
    //2.創建共有對象 
    private Exchanger<String> ex;

    //3.創建類的 有參構造,傳入參數
    public B(Exchanger<String> ex) {
        this.ex = ex;
    }

    //4.重寫run方法
    @Override
    public void run() {
        String str = null ;
        try {
            str = ex.exchange("Hey?"); //準備要交換的數據
            System.out.println("B的數據:"+str);

            str = ex.exchange("1"); //準備要交換的數據
            System.out.println("B的數據:"+str);

            str = ex.exchange("2"); //準備要交換的數據
            System.out.println("B的數據:"+str);

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

Exchanger - 運行結果

這裏寫圖片描述

Exchanger - 使用總結

Exchanger 同步器特性
    1.兩條線程 數據的相互交換

Exchanger API的應用以及書寫方式
    功能類
        1.創建兩個線程類 
        2.在兩條線程類中完成功能,使用 ex.exchange("Hello?"); 準備要交換的數據
    調用類:
        1.Exchanger<String> ex = new Exchanger<>(); //創建 Exchanger對象實例,並指定交換數據的類型。
        2.調用功能類即可。

同步器 - Phaser(相位器)

Phaser - API

這裏寫圖片描述

Phaser - 演示代碼

package com.phaser.demo1;

import java.util.concurrent.Phaser;

/**
 * 演示目標:模擬餐廳服務
 *  條件:
 *      1,有三位客人
 *      2. 有三個服務環節:服務員(接待)、廚師(做菜)、傳菜(給客人上菜)
 * */
public class DemoCase {
    public static void main(String[] args) {
        Phaser phaser = new Phaser(1); // Phaser對象實例,管理併發線程

        System.out.println("準備啓動。。。");

        //創建併發線程對象
        new Worker(phaser, "服務員").start();
        new Worker(phaser, "廚師").start();
        new Worker(phaser, "上菜").start();

        //控制併發線程,當有線程沒執行完 等待 (循環處理三位客人就餐)
        for (int i = 1; i <=3; i++) {
            System.out.println(i+"號訂單開始處理");
            phaser.arriveAndAwaitAdvance();//等待

        }

        //當所有併發線程都執行完,註銷
        phaser.arriveAndDeregister(); //註銷
        System.out.println("All Done!");
    }
}
/**
 * 功能類: 
 *  實現了每個崗位的工作
 * */   
//1.繼承 Thread類
class Worker extends Thread
{
    //2,創建共有的對象 
    private Phaser phaser ;

    //3.創建類的有參構造函數,傳入參數
    public Worker(Phaser phaser ,String name)
    {
        setName(name);
        this.phaser = phaser;

        phaser.register(); //註冊
    }

    //4.重寫run方法
    @Override
    public void run() 
    {
        //假設有三個訂單,所以每個崗位都運行了三遍
        for(int i = 1; i<=3; i++)
        {
            System.out.println("當前服務的是:"+getName());//提示消息,

            if(i == 3)//當前崗位三次工作完成 ,註銷自己
            {
                phaser.arriveAndDeregister(); //註銷 
            }else //如果當前崗位沒有完成3次工作,等待完成。
            {
//              System.out.println(getName()+"等待。。。");
                phaser.arriveAndAwaitAdvance(); //等待
            }

            //爲了看出效果,做一個休眠,每一秒 當前崗位操作一次
            try 
            {
                Thread.sleep(1000);
            } catch (InterruptedException e) 
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
         }
    }
}

Phaser - 運行結果

這裏寫圖片描述

Phaser - 使用總結

Phaser 同步器特性
    工作方式與CyclicBarrrier類似,但是可以定義多個階段
Phaser 的API的使用
    1,首先在類的構造方法中先註冊 phaser.register(); //註冊
    2. 其次有兩種情況
       當線程沒有執行完,可以等待  phaser.arriveAndAwaitAdvance(); //等待
       當線程執行完,要註銷自己 phaser.arriveAndDeregister(); //註銷 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章