Java多線程總結

在Java的線程編寫,大部分能夠用成熟的工具類來實現。java

1.ThreadLocal(線程範圍內的共享數據)

ThreadLocal<Integer> x = new ThreadLocal<Integer>();

一個線程有一個空間能夠共享。能夠利用泛型設計複雜的數據結構數組

也能夠利用這個設計線程的單例模式數據結構

/**
 * @author wengwh
 * @Date 2014-8-4
 */
public class MyThreadScopeData {
    private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();

    private MyThreadScopeData() {
    };

    public static MyThreadScopeData getThreadInstance() {
        MyThreadScopeData instance = map.get();
        if (instance == null) {
            instance = new MyThreadScopeData();
            map.set(instance);
        }
    }
}

2.線程池

jdk提供了幾種類型的線程池,能夠根據須要選擇其中一種。併發

ExecutorService threadPool = Executors.newFixedThreadPool(3);
threadPool.execute(new Runnable() {
    
    @Override
    public void run() {
        
    }
});

3.Callable與Future

Future取得的結果類型和Callable返回的結果類型必須一致,這是經過泛型來實現的。dom

Callable要採用ExecutorService的submit方法提交,返回的future對象能夠取消任務。ide

CompletionService用於提交一組Callable任務,其task方法返回已完成的一個Callable任務對應的Future對象。工具

Future<String> future = threadPool.submit(new Callable<String>() {
        public String call() {
            return "hello";
        }
    });
try {
    System.out.println(future.get());
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}

4.Lock鎖

比較簡單的示例性能

Lock lock = new ReentrantLock();
lock.lock();
try{
    for(int i=0;i<10;i++){
        System.out.println(i);
    }
}finally{
    lock.unlock();
}

5.讀寫鎖

讀寫鎖就是一種,能夠同時讀,不能同時讀寫,寫寫ui

代碼示例:線程

ReentrantReadWriteLock writeLock = new ReentrantReadWriteLock();
writeLock.readLock().lock();
writeLock.readLock().unlock();
writeLock.writeLock().lock();
writeLock.readLock().lock();
writeLock.writeLock().unlock();
writeLock.readLock().unlock();

6.Condition

Condition的功能相似在傳統線程技術中的Object.wait和Object.notify的功能

能夠經過定義2個condition對象來實現生產者模式

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();
condition.await();
condition.signal();
lock.unlock();

7.Semaphore

Semaphore能夠維護當前訪問自身的線程個數,並提供了同步機制。使用Semaphore能夠控制同時訪問資源的線程個數,例如:實現一個文件容許的併發訪問數。

Semaphore sp = new Semaphore(3);
sp.acquire();獲取一個信號
sp.release();釋放一個信號

8.CyclicBarrier

CyclicBarrier是要等到所有的線程都到達纔會一塊兒進行下去

例子:直接到有3個都到達了纔會繼續下一個

final CyclicBarrier cb = new CyclicBarrier(3);
for(int i=0;i<3;i++){
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            try {
                Thread.sleep((long)Math.random()*10000);
                System.out.println(cb.getNumberWaiting());
                cb.await();
                System.out.println("end");
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };
    Thread thread = new Thread(runnable);
    thread.start();
}

9.CountDownLatch(倒計時器)

cdOrder.countDown();計數器減一
cdOrder.await();計數器爲0時候觸發

10.Exchanger(兩個線程之間的數據交換)

final Exchanger<String> exchanger = new Exchanger<>();
for(int i=0;i<2;i++){
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            try {
                
                System.out.println("start-"+Thread.currentThread().getName());
                System.out.println(exchanger.exchange(Thread.currentThread().getName())+Thread.currentThread().getName());
                System.out.println("end-"+Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    Thread thread = new Thread(runnable);
    thread.start();
}

11.隊列

隊列是一種數據結構.它有兩個基本操做:在隊列尾部加人一個元素,和從隊列頭部移除一個元素就是說,隊列以一種先進先出的方式管理數據。Queue接口與List、Set同一級別,都是繼承了Collection接口。LinkedList實現了Queue接口。Queue接口窄化 了對LinkedList的方法的訪問權限(即在方法中的參數類型若是是Queue時,就徹底只能訪問Queue接口所定義的方法了,而不能直接訪問 LinkedList的非Queue的方法),以使得只有恰當的方法纔可使用。BlockingQueue 繼承了Queue接口。

幾種阻塞隊列:

LinkedBlockingQueue的容量默認是沒有上限的(在不指定時容量爲Integer.MAX_VALUE),也能夠選擇指定其最大容量,它是基於鏈表的隊列,此隊列按 FIFO(先進先出)排序元素。

ArrayBlockingQueue在構造時須要指定容量,並能夠選擇是否須要公平性(默認false),若是公平參數 被設置true,等待時間最長的線程會優先獲得處理(其實就是經過將ReentrantLock設置爲true來達到這種公平性的:即等待時間最長的線程 會先操做)。一般,公平性會使你在性能上付出代價,只有在的確很是須要的時候再使用它。它是基於數組的阻塞循環隊列,此隊列按 FIFO(先進先出)原則對元素進行排序。

PriorityBlockingQueue是一個帶優先級的隊列,而不是先進先出隊列。元素按優先級 順序被移除,該隊列也沒有上限(看了一下源碼,PriorityBlockingQueue是對PriorityQueue的再次包裝,是基於堆數據結構 的,而PriorityQueue是沒有容量限制的,與ArrayList同樣,因此在優先阻塞隊列上put時是不會受阻的,可是若是隊列爲空,取元素的操做take就會阻塞。另外,往入該隊列中的元 素要具備比較能力。

DelayQueue(基於PriorityQueue來實現的)是一個存放Delayed 元素的無界阻塞隊列,只有在延遲期滿時才能從中提取元素。該隊列的頭部是延遲期滿後保存時間最長的 Delayed 元素。若是延遲都尚未期滿,則隊列沒有頭部,而且poll將返回null。當一個元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一個小於或等於零的值時,則出現期滿,poll就以移除這個元素了。此隊列不容許使用 null 元素。

12.同步集合

Collections工具類

注意:在集合的迭代過程當中,不能對集合進行刪除操做 這個時候能夠用CopyOnWriteArrayList

相關文章
相關標籤/搜索