Concurrent包工具类使用
一。讀寫鎖
傳統的同步鎖就是獨占式鎖,當線程使用資源時候保持獨占,無論讀寫。當人們發現請求隊列(假設)中相鄰請求為讀-讀的時候,阻塞是一種浪費資源的操作。比如公告板,所有路過的人(請求)都是讀操作,并沒有因為你和他在讀的時候對內容造成了改變,所以在模型中,讀與讀操作不需要阻塞。而讀寫相鄰則需要進行獨占式操作了,因為寫未完成的時候,信息是不完整的,此時讀出來的信息有可能是錯誤的,所以寫必然要保持獨占式操作。而在應用程序中,讀的頻率是寫的好幾倍,也就是說如果讀-讀是不阻塞的,那么對性能來說是毋庸置疑的提升。
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() {@Overridepublic void run() {try{System.out.println("read:"+demo.handleRead(readLock));}catch (Exception e){e.printStackTrace();}}};Runnable writeThread = new Runnable() {@Overridepublic 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個讀寫操作,如果使用了讀操作,則打印的讀操作是連續的;如果使用了重入鎖,則可能的情況是讀寫相鄰打印,并且都是阻塞的,讀者可以自行測試體會。
二。對象監視器Condition
在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方法才會過去。
四。信號量
信號量這個東西就比較玄乎了,有點像準入許可,拿到信號準入的時候才往下執行。就像是有一批人拿號,只有號碼區間在某個范圍的人能進去辦事,然后辦完事就會讓資源釋放,號碼區間往后移。然而在信號量中應該算是復用類型的,歸還了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高并發程序設計》的讀書筆記
?
轉載于:https://www.cnblogs.com/chentingk/p/8540823.html
總結
以上是生活随笔為你收集整理的Concurrent包工具类使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何实现文件增量同步——算法
- 下一篇: MySQL源码学习——DBUG调试