並發包使用和解釋


什么是並發包(JDK1.5提出):收集了各種專門在多線程情況下使用,並且可以保證線程安全的一些類

CopyOnWriteArrayList

普通並發下的List

public class CopyOnWrite {
    static List<Integer> list = new ArrayList<>();
    public static void main(String[] args) {
        demo1();
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }

    public static void demo1(){
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    list.add(i);
                }
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    list.add(i);
                }
            }
        }.start();
    }
}

結果:

 

 

 解決方法使用:CopyOnWriteArrayList是線程安全的

public static CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();

Set使用CopyOnWriteArraySet

 public static CopyOnWriteArraySet<Integer> set = new CopyOnWriteArraySet<>();

MapConcurrentHashMap

public static Hashtable<Integer, Integer> map = new Hashtable<>();

對於HaseTable

但是HashTable有兩個性能上的問題:
a.無腦加鎖,無論是添加,刪除,獲取都加鎖,並使用同一個鎖對象,導致性能極其低下
b.HashTable添加是全局鎖,有且僅有一個線程可以操作HashTable,導致性能極其低下

 

多線程並發問題關鍵字

自從JDK5發布以來,在java.util.concurrent包中提供了一些非常有用的輔助類來幫助我們進行並發編程,下面就介紹一下這些輔助類中的Semaphore、CyclicBarrier、CountDownLatch以及Exchanger的相關用法

1.CountDownLatch

  CountDownLatch可以實現類似計數器的功能,計數器的初始值為指定的線程的數量,每當一個線程完成了自己的任務,計數器的值就會減1,當計數器的值達到了0時,它表示所有的線程都完成了任務,然后在閉鎖上等待的線程就可以恢復執行任務。構造器上的計數值實際上就是閉鎖需要等待的線程數量,這個值只能被設置一次,而且CountDownLatch沒有提供任何機制去重新設置這個值。

構造方法:
    public CountDownLatch(int count);指定計數的線程
成員方法:
    public void await();讓當前線程等待
    public void countDown();減少需要等待的線程數量  
public class BengTest {
    static CountDownLatch downLatch = new CountDownLatch(1);
    static CountDownLatch downLatch2 = new CountDownLatch(1);
    public static void main(String[] args) {
        demo1();
    }

    public static void demo1(){
        new Thread(){
            @Override
            public void run() {
                System.out.println("起床");
                downLatch.countDown();
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                try {
                    downLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("洗臉");
                downLatch2.countDown();
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                try {
                    downLatch2.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("出門");
            }
        }.start();
    }

}

 

2.CyclicBarrier

CyclicBarrier直譯過來叫做內存屏障,它要做的事情是,讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最后一個線程到達屏障時,屏障才會開門,所有被屏障攔截的線程才會繼續下面的業務。

構造方法:
    public CyclicBarrier(int parties, Runnable barrierAction);
    參數1:parties表示這組線程的數量!
    參數2:barrierAction 表示一組線程都到達之后需要執行的任務!     

成員方法:
    public int await(); 讓當前線程阻塞
/**
 * @program: study_java
 * @description: test
 * @author: xiaozhang6666
 * @create: 2020-06-22 13:44
 **/
public class BengTest {
    static CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
        @Override
        public void run() {
            System.out.println("觸發屏障后程序");
        }
    });
    public static void main(String[] args) {
        demo2();
    }

    public static void demo2(){
        new Thread(){
            @Override
            public void run() {
                System.out.println("屏障1");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                System.out.println("屏障2");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

}

 

3.Semaphore

emaphore是計數信號量,是操作系統中的一個概念,經常用於限制獲取某種資源的線程數量,在new 這個類的時候需要給這個類傳遞一個參數permits,這個參數是整數類型,這個參數的意思是同一時間內,最多允許多少個線程同時執行acquire方法和release方法之間的代碼,如果方法acquire沒有參數則默認是一個許可。

構造方法:
public Semaphore(int permits);
        參數permits稱為許可證,即最大的線程並發數量
成員方法:
public void acquire(); 表示獲取許可證
public void release(); 釋放許可證   
package day17.package_homework;

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

/**
 * @program: study_java
 * @description: test
 * @author: xiaozhang6666
 * @create: 2020-06-22 13:44
 **/
public class BengTest {
    static Semaphore semaphore = new Semaphore(1);

    public static void main(String[] args) {
        demo3();
    }

    public static void demo3() {
        new Thread() {
            @Override
            public void run() {
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("線程一開始");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("線程一結束...");
                semaphore.release();
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("線程二開始");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("線程二結束...");
                semaphore.release();
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("線程三開始");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("線程三結束...");
                semaphore.release();
            }
        }.start();
    }

}

 

4.Exchanger

Exchanger是用於線程間協作的工具類,用於線程間的數據交換,它提供一個同步點,在這個同步點兩個線程可以交換彼此的數據。這兩個線程通過exchange方法交換數據, 如果第一個線程先執行exchange方法,它會一直等待第二個線程也執行exchange,當兩個線程都到達同步點時,這兩個線程就可以交換數據,將本線程生產出來的數據傳遞給對方。

構造方法:
    public Exchanger();
成員方法:
    public V exchange(V x);//交換數據
public class ThreadA extends Thread {
    private Exchanger<String> exchanger;
    public ThreadA(Exchanger<String> exchanger){
        this.exchanger = exchanger;
    }

    @Override
    public void run() {
        try {
            //線程A給線程B發信息
            System.out.println("線程A給線程B發信息...");
            String exchange = exchanger.exchange("AAAAAAAAAAAA");
            System.out.println("同時獲取到線程B的回信:"+exchange);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
public class ThreadB extends Thread {
    private Exchanger<String> exchanger;
    public ThreadB(Exchanger<String> exchanger){
        this.exchanger = exchanger;
    }

    @Override
    public void run() {
        try {
            //線程B給線程A發信息
            System.out.println("線程B給線程A發信息...");
            String exchange = exchanger.exchange("BBBBBBBBBBBBBBBB");
            System.out.println("同時獲取到線程A的回信:"+exchange);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

public class TestDemo {
    public static void main(String[] args) {
        //1.創建Exchanger
        Exchanger<String> exchanger = new Exchanger<String>();

        //2.創建線程AB
        ThreadA a = new ThreadA(exchanger);
        ThreadB b = new ThreadB(exchanger);

        //3.開啟線程A
        a.start();
        b.start();

    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM