Java并发程序设计(四)JDK并发包之同步控制
JDK并發(fā)包之同步控制
一、重入鎖
重入鎖使用java.util.concurrent.locks.ReentrantLock來實現(xiàn)。示例代碼如下:
public class TryReentrantLock implements Runnable{static ReentrantLock lock=new ReentrantLock();static int i=0;@Overridepublic void run() {for(int j=0;j<10000;j++){lock.lock();try{i++;}finally {lock.unlock();}//重入鎖可以反復(fù)進(jìn)入,當(dāng)然這種進(jìn)入僅限于一個線程!因此可以如下:/*lock.lock(); lock.lock();try{i++;}finally {lock.unlock();lock.unlock();}*/}}public static void main(String[] args) throws InterruptedException {TryReentrantLock l=new TryReentrantLock();Thread t1=new Thread(l);Thread t2=new Thread(l);t1.start(); t2.start();t1.join(); t2.join();System.out.println(i);} }對于synchronized來說,如果一個線程在等待鎖,那么結(jié)果只有兩種情況,要么它獲得這把鎖繼續(xù)執(zhí)行,要么繼續(xù)等待鎖。而對于使用重入鎖的線程來說則不同,線程在等待鎖的過程中,程序可以根據(jù)需要取消對鎖的請求。
public class IntLock implements Runnable{public static ReentrantLock lock1=new ReentrantLock();public static ReentrantLock lock2=new ReentrantLock();int state;/*控制加鎖順序,便于產(chǎn)生死鎖。*/public IntLock(int state){this.state=state;}@Overridepublic void run() {try{if(state==1){lock1.lockInterruptibly(); //設(shè)置可中斷的鎖try{Thread.sleep(500); //便于產(chǎn)生死鎖}catch (InterruptedException e){e.printStackTrace();}lock2.lockInterruptibly();}else{lock2.lockInterruptibly();try{Thread.sleep(500);}catch (InterruptedException e){e.printStackTrace();}lock1.lockInterruptibly();}}catch (Exception e){e.printStackTrace();}finally {if(lock1.isHeldByCurrentThread()) lock1.unlock();if(lock2.isHeldByCurrentThread()) lock2.unlock();System.out.println(Thread.currentThread().getName()+" :quit!");}}public static void main(String[] args) throws InterruptedException {IntLock intLock1=new IntLock(1);IntLock intLock2=new IntLock(2);Thread t1=new Thread(intLock1);t1.setName("t1");Thread t2=new Thread(intLock2);t2.setName("t2");t1.start(); t2.start();Thread.sleep(1000);t2.interrupt();} }使用tryLock()進(jìn)行限時等待。
public class TimeLock implements Runnable{public static ReentrantLock lock=new ReentrantLock();@Overridepublic void run() {try{if(lock.tryLock(5, TimeUnit.SECONDS)){//注意返回布爾值.如果使用無參數(shù)的tryLock方法,// 當(dāng)鎖被占用時,線程會不等待,并返回false。Thread.sleep(6000);}else{System.out.println("Get lock failed!");}}catch (Exception e){e.printStackTrace();}finally {if (lock.isHeldByCurrentThread()) lock.unlock();}}public static void main(String[] args){TimeLock timeLock=new TimeLock();Thread t1=new Thread(timeLock);Thread t2=new Thread(timeLock);t1.start();t2.start();} }?
公平鎖:
大多數(shù)情況下,鎖的申請都是不公平,隨機(jī)的。而公平鎖,講究“先來后到”!因此公平鎖的一大特點是不會產(chǎn)生饑餓。重入鎖允許我們對其公平性進(jìn)行設(shè)置:
public ReentrantLock(boolean fair); //true表示公平鎖公平鎖缺點:性能相對低下。
?
二、重入鎖的好基友Condition
Condition的做用類似于wait()和notify()只不過Condition和ReentrantLock配合。
Condition接口的基本方法:
void await() throws InterruptedException //釋放當(dāng)前線程持有的鎖,進(jìn)入等待狀態(tài),當(dāng)其他線程使用signal或signalAll()方法時繼續(xù)執(zhí)行。當(dāng)線程被中斷時會跳出等待。void awaitUninterruptibly();與await()方法相似,當(dāng)中斷時不會跳出等待。void signal(); void signalAll();用法示例:
public class ReentrantCondition implements Runnable{static ReentrantLock lock=new ReentrantLock();static Condition condition=lock.newCondition();@Overridepublic void run() {try{lock.lock();System.out.println(Thread.currentThread().getName()+" is running fast!");condition.await();System.out.println(Thread.currentThread().getName()+" is going no.");}catch (InterruptedException e){e.printStackTrace();}finally {lock.unlock();}}public static void main(String[] args) throws InterruptedException {ReentrantCondition rc=new ReentrantCondition();Thread t=new Thread(rc,"King of Lock");t.start();Thread.sleep(2000);lock.lock(); //調(diào)用signal前先要獲得鎖 condition.signal();lock.unlock(); //調(diào)用singal后要釋放鎖,以讓給被喚醒的線程。 } }?
三、允許多個線程同時訪問:信號量(Semaphore)
Semaphore可以指定多個線程同時訪問一個資源。
public Semaphore(int permits); //permits指定同時能有幾個線程訪問同一資源。 public Semaphore(int permits,boolean fair) //fair指定是否采用公平鎖Semaphore主要的邏輯方法有:
public void acquire() //嘗試獲得一個準(zhǔn)入許可,若無法獲得,則線程會等待,直到有線程釋放了一個許可,或者當(dāng)前線程被中斷 public void acquireUninterruptibly() //不響應(yīng)中斷 public void release() //釋放一個許可?
四、ReadWriteLock讀寫鎖
讀寫鎖允許多個線程同時讀。
?
五、CountDownLatch倒計時器
通常用來控制線程等待,可以讓某個線程等待直到倒計時結(jié)束,再開始執(zhí)行。
public CountDownLatch(int count) //count為需要完成幾個線程上的任務(wù),CountDownLatch上的線程才能繼續(xù)執(zhí)行。?
?示例代碼:
public class CountDownLatchDemo implements Runnable{static final CountDownLatch latch=new CountDownLatch(10); //需要完成10個線程的任務(wù),// CountDownLatch上的線程才能繼續(xù)執(zhí)行static final CountDownLatchDemo demo=new CountDownLatchDemo();@Overridepublic void run() {try{Thread.sleep(1000);System.out.println(Thread.currentThread().getName()+" :mission completed!");latch.countDown();//通知CountDownLatch一個任務(wù)已經(jīng)完成。}catch (Exception e){e.printStackTrace();}}public static void main(String[] args) throws InterruptedException {ExecutorService ex= Executors.newFixedThreadPool(10);for(int i=0;i<10;i++){ex.submit(demo);}latch.await(); //設(shè)置要等待其他線程完成的那個線程System.out.println("Killed them all!");ex.shutdown();} }?
六、循環(huán)柵欄:CyclicBarrier
與CountDownLatch類似CyclicBarrier也是用來阻止線程繼續(xù)執(zhí)行,讓線程進(jìn)入等待狀態(tài)。但此計數(shù)器可以反復(fù)使用。
public CyclicBarrier(int parties,Runnable barrierAction) //barrierAction為計數(shù)完成后要執(zhí)行的動作示例代碼:
public class CyclicBarrierDemo {public static class Soldier implements Runnable{private String name;private final CyclicBarrier barrier;Soldier(String name,CyclicBarrier barrier){this.name=name;this.barrier=barrier;}@Overridepublic void run() {try{barrier.await(); //進(jìn)入等待狀態(tài),直到所有線程完成計數(shù)。doWork(); //所有線程完成一次await,繼續(xù)執(zhí)行。barrier.await(); //第二次await再次進(jìn)入等待狀態(tài)。}catch (Exception e){}}void doWork(){try{Thread.sleep(Math.abs(new Random().nextInt()%10000));}catch (Exception e){e.printStackTrace();}System.out.println("任務(wù)完成!");}}public static class FlyRun implements Runnable{boolean flag;int count;public FlyRun(boolean flag,int count){this.flag=flag;this.count=count;}@Overridepublic void run() {if (flag) System.out.println("隊長:"+count+" 個士兵完成任務(wù)!");else {System.out.println("隊長:"+count+" 個士兵集合完畢!");flag=true;}}}public static void main(String[] args){final int count=12;Thread[] soldiers=new Thread[count];boolean flag=false;CyclicBarrier barrier=new CyclicBarrier(count,new FlyRun(flag,count));//集合隊伍System.out.println("集合隊伍!");for(int j=0;j<count;j++){System.out.println("士兵"+j+"報道!");soldiers[j]=new Thread(new Soldier("士兵"+j,barrier));soldiers[j].start();}} }?
七、線程阻塞工具類:LockSupport
LockSupport可以在線程內(nèi)任意位置讓線程阻塞。但與Object.wait()不同,它不需要先獲得某個對象的鎖,也不會拋出InterruptedException異常。示例代碼:
public class LockSupportDemo {public static Object instance=new Object();public static ChangThread t1=new ChangThread("t1");public static ChangThread t2=new ChangThread("t2");public static class ChangThread extends Thread{public ChangThread(String name){super.setName(name);}@Overridepublic void run(){synchronized(instance){System.out.println("in"+getName());LockSupport.park();}}}public static void main(String[] args) throws InterruptedException {t1.start();Thread.sleep(100);t2.start();LockSupport.unpark(t1); //即使unpark()發(fā)生在park前,程序也能正常執(zhí)行。 LockSupport.unpark(t2);t1.join();t2.join();} }park還支持中斷影響,且不拋出異常。
?
轉(zhuǎn)載于:https://www.cnblogs.com/Shadowplay/p/7459166.html
總結(jié)
以上是生活随笔為你收集整理的Java并发程序设计(四)JDK并发包之同步控制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转载】Apache Spark Job
- 下一篇: 远程桌面连接mstsc 超扎心