Concurrent包工具類使用

一。讀寫鎖java

  傳統的同步鎖就是獨佔式鎖,當線程使用資源時候保持獨佔,不管讀寫。當人們發現請求隊列(假設)中相鄰請求爲讀-讀的時候,阻塞是一種浪費資源的操做。好比公告板,全部路過的人(請求)都是讀操做,並無由於你和他在讀的時候對內容形成了改變,因此在模型中,讀與讀操做不須要阻塞。而讀寫相鄰則須要進行獨佔式操做了,由於寫未完成的時候,信息是不完整的,此時讀出來的信息有多是錯誤的,因此寫必然要保持獨佔式操做。而在應用程序中,讀的頻率是寫的好幾倍,也就是說若是讀-讀是不阻塞的,那麼對性能來講是毋庸置疑的提高。多線程

  Java中存在一種鎖,名曰:ReentrantReadWriteLock。他能夠實現內存中對資源操做的讀寫鎖,讀與讀是不阻塞的。併發

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by MacBook on 2018/3/10.
 */
public class ReadWriteLockDemo {
    private static Lock relock = new ReentrantLock();
    private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private static Lock readLock = readWriteLock.readLock();
    private static Lock writeLock = readWriteLock.writeLock();
    private int value;
    public Object handleRead(Lock lock) throws Exception{
        try{
            lock.lock();
            Thread.sleep(1000);
            return value;
        }finally {
            lock.unlock();
        }
    }
    public void handleWrite(Lock lock,int index) throws Exception{
        try{
            lock.lock();
            Thread.sleep(1000);
            value = index;
        }finally {
            lock.unlock();
        }
    }
    public static void main(String[] args){
        ReadWriteLockDemo demo = new ReadWriteLockDemo();
        Runnable readThread = new Runnable() {
            @Override
            public void run() {
                try{
                    System.out.println("read:"+demo.handleRead(readLock));
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        };
        Runnable writeThread = new Runnable() {
            @Override
            public void run() {
                try{
//                    demo.handleWrite(relock,new Random().nextInt());
                    demo.handleWrite(writeLock,new Random().nextInt());
                    System.out.println("id:"+Thread.currentThread().getId()+" done!");
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        };
        for(int i=0;i<18;i++){
            new Thread(readThread).start();
        }
        for(int i=0;i<18;i++){
            new Thread(writeThread).start();
        }
    }

}

    此demo使用了重入鎖和讀寫鎖的對比,在主程序中分別新建18個讀寫操做,若是使用了讀操做,則打印的讀操做是連續的;若是使用了重入鎖,則可能的狀況是讀寫相鄰打印,而且都是阻塞的,讀者能夠自行測試體會。dom

二。對象監視器Conditionide

  在JDK實現了Lock來簡化synchronized以後,Condition做爲簡化監視器而存在。Condition的await方法和signal方法對應對象的wait和signal。高併發

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by MacBook on 2018/3/10.
 */
public class ConditionAndLock implements Runnable{
    static ReentrantLock lock = new ReentrantLock();
    static Condition condition = lock.newCondition();

    public void run(){
        try{
            lock.lock();
            condition.await();
            System.out.println("thread is running");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public static void main(String[] args){
        ConditionAndLock c = new ConditionAndLock();
        Thread t = new Thread(c);
        t.start();
        lock.lock();
        System.out.println("signal all");
        condition.signalAll();
        lock.unlock();
    }
}

三。倒計時器CountDownLatch性能

  多線程中,須要知道這批線程的最大完成任務時間,也就是從第一個任務開始到最後返回這段時間的時長,那麼倒計時器是必不可少的。就像各項資源準備完畢才進行下一步操做的模型同樣,CountDownLatch就是這樣的多線程模型。等到全部任務調用了計數器,而且計數器總數到達某個數量時候,它纔會將阻塞代碼放開,讓主線程往下走。測試

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 倒計時器
 * Created by MacBook on 2018/3/10.
 */
public class CountDownLatchDemo implements Runnable{
    static CountDownLatch end = new CountDownLatch(10);
    static CountDownLatchDemo demo = new CountDownLatchDemo();
    public void run(){
        try{
            Thread.sleep(new Random().nextInt(10)*1000);
            System.out.println(Thread.currentThread().getId()+" check complete!");
            end.countDown();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws Exception{
        ExecutorService service = Executors.newFixedThreadPool(10);
        for(int i=0;i<10;i++){
            service.submit(demo);
        }
        end.await();
        System.out.println("fire");
        service.shutdown();
    }
}

    await方法是阻塞倒計時器所在線程的方法,等到線程池service中調用countDown方法到達必定的數量(此處是10)以後,主線程的await方法纔會過去。ui

四。信號量this

  信號量這個東西就比較玄乎了,有點像准入許可,拿到信號准入的時候才往下執行。就像是有一批人拿號,只有號碼區間在某個範圍的人能進去辦事,而後辦完事就會讓資源釋放,號碼區間日後移。然而在信號量中應該算是複用類型的,歸還了key值,將key值返回給下一個申請者。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * Created by MacBook on 2018/3/10.
 */
public class SemapDemo implements Runnable{
    final Semaphore semp = new Semaphore(5);
    public void run(){
        try{
            semp.acquire();
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getId()+" done!");
            semp.release();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args){
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        SemapDemo semapDemo = new SemapDemo();
        for(int i=0;i<20;i++){
            executorService.submit(semapDemo);
        }
        executorService.shutdown();
    }
}

  在acquire得到key以後,操做讀寫,以後release。

五。柵欄

  柵欄和倒計時器很像,就是攔住一堆線程,等到線程數達到某個設定值以後同時把它們放出去。可是不一樣的是,它能夠每次設定值達成時候運行定製線程中的run方法。就像是每次一個欄,夠數就放。

import java.util.Random;
import java.util.concurrent.CyclicBarrier;

/**
 * Created by MacBook on 2018/3/10.
 */
public class CylicBarrierDemo {
    public static class Soldier implements Runnable{
        private String soldier;
        private final CyclicBarrier cyclicBarrier;
        Soldier(String soldier,CyclicBarrier cyclicBarrier){
            this.soldier = soldier;
            this.cyclicBarrier = cyclicBarrier;
        }
        public void run(){
            try{
                cyclicBarrier.await();
                doWork();
                cyclicBarrier.await();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        public void doWork(){
            try{
                Thread.sleep(Math.abs(new Random().nextInt()%10000));
            }catch (Exception e){
                e.printStackTrace();
            }
            System.out.println(soldier + " done!");
        }
    }
    public static class BarrierRun implements Runnable{
        boolean flag;
        int n;
        public BarrierRun(boolean flag,int n){
            this.flag = flag;
            this.n = n;
        }

        public void run(){
            if(flag){
                System.out.println("士兵:"+n+"個 done!");
            }else {
                System.out.println("士兵:"+n+"個 集合完畢!");
                flag = true;
            }
        }
    }
    public static void main(String[] args){
        final int n = 10;
        Thread[] allSoldier = new Thread[n];
        boolean flag = false;
        CyclicBarrier cyclic = new CyclicBarrier(n,new BarrierRun(flag,n));
        System.out.println("集合");
        for(int i =0; i < n ; i++){
            System.out.println("士兵 "+i+" 報道");
            allSoldier[i] = new Thread(new Soldier("士兵"+i,cyclic));
            allSoldier[i].start();
        }
    }
}

  例中CyclicBarrier有兩個參數,前一個就是提到的設定值,後一個就是定製線程了。每當到達設定值的時候會觸發定製線程。

  每一個階段完成都會調用一下定製線程。

六。LockSupport提供線程掛起操做的支持類

  正如Condition使得原有的Object監視器封裝成了新類,LockSupport提供使線程park和unpark之類的操做。

import java.util.concurrent.locks.LockSupport;

/**
 * Created by MacBook on 2018/3/10.
 */
public class LockSupportDemo {
    public static Object u = new Object();
    static ChangeObjectThread t1 = new ChangeObjectThread("t1");
    static ChangeObjectThread t2 = new ChangeObjectThread("t2");
    public static class ChangeObjectThread extends Thread{
        public ChangeObjectThread(String name){
            super.setName(name);
        }
        public void run(){
            synchronized (u){
                System.out.println("in "+getName());
                LockSupport.park();
            }
        }
    }
    public static void main(String[] args) throws Exception{
        t1.start();
        Thread.sleep(100);
        t2.start();
        LockSupport.unpark(t1);
        LockSupport.unpark(t2);
        t1.join();
        t2.join();
    }

}

  它在park時候線程會變成wait狀態,而不是runnable。

 

  來自《Java高併發程序設計》的讀書筆記

相關文章
相關標籤/搜索