AQS理解之二,自己设计一个锁
生活随笔
收集整理的這篇文章主要介紹了
AQS理解之二,自己设计一个锁
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
AQS理解之二,自己設計一個鎖
一,實現鎖的條件
首先我們想一想,如果我們自己實現一個類似于java中的鎖,我們可能需要哪些必要的東西:
1,記錄是哪個線程持有了鎖。
2,如果有一個變量代表加鎖,A線程加鎖,需要讓B線程能看見,這里需要可見性,所以我們可能要用到volatile變量。
3,對變量的操作應該是一個原子操作。
二,實現
首先我們定義一個類,這個類需要有一個持有鎖的變量。這里使用ownerThread這個變量來代表持有鎖的線程。
class MyLock{private Thread ownerThread;public Thread getOwnerThread() {return ownerThread;}public void setOwnerThread(Thread ownerThread) {this.ownerThread = ownerThread;} }我們先簡單定義一下加鎖和解鎖的方法。并設置一個volatile的變量來保證鎖的可見性。
class MyLock{private Thread ownerThread;private volatile int state;public Thread getOwnerThread() {return ownerThread;}public void setOwnerThread(Thread ownerThread) {this.ownerThread = ownerThread;}public boolean lock(){//可重入,如果鎖設置不可重入,則state應該只能為1和0,并在此處拋出異常。if (Thread.currentThread() == getOwnerThread()){//臨時寫法,應該為原子操作的++;state++;return true;} else if(state == 0){state++; //這里的判斷相等和++操作不應該分開,臨時寫法。正確方法應該為CAS操作。setOwnerThread(Thread.currentThread());return true;}return false;}public void unlock(){if (Thread.currentThread() != getOwnerThread()){throw new RuntimeException("不是鎖持有線程,不能解鎖");}state--;setOwnerThread(null);} }這里我們看到lock里我們考慮到了可重入性,所以簡單實現了一下,如果還要實現lock阻塞,應該加上自旋操作,如:
public boolean lock(){//加上自旋,如果失敗,繼續。for (;;) {if (Thread.currentThread() == getOwnerThread()){state++;return true;}else if(state == 0){state++;setOwnerThread(Thread.currentThread());return true;}} }我們繼續完善代碼,將之前的臨時操作進一步優化。因為我們無法使用unsafe類來操作,我門這里將state修改為AtomicInteger。
class MyLock{private Thread ownerThread;private volatile AtomicInteger state;public MyLock(){state = new AtomicInteger(0);}public Thread getOwnerThread() {return ownerThread;}public void setOwnerThread(Thread ownerThread) {this.ownerThread = ownerThread;}public boolean lock(){//可重入for (;;) {if (Thread.currentThread() == getOwnerThread()){state.incrementAndGet();return true;}else if(state.compareAndSet(0,1)){setOwnerThread(Thread.currentThread());}}}public void unlock(){if (Thread.currentThread() != getOwnerThread()){throw new RuntimeException("不是鎖持有線程,不能解鎖");}setOwnerThread(null);state.decrementAndGet();} }三,驗證
public static void testSout(){try{lock.lock();System.out.println("a");Thread.sleep(100);System.out.println("b");Thread.sleep(100);System.out.println("c");Thread.sleep(100);System.out.println("d");Thread.sleep(100);}catch (Exception e){e.printStackTrace();}finally {lock.unlock();} }public static void main(String[] args) throws InterruptedException {Runnable runnable = new Runnable() {@Overridepublic void run() {TestUtil.testSout();}};Thread thread = new Thread(runnable);Thread thread1 = new Thread(runnable);Thread thread2 = new Thread(runnable);Thread thread3 = new Thread(runnable);thread.start();thread1.start();thread2.start();thread3.start();thread.join();thread1.join();thread2.join();thread3.join();}控制臺可以正常輸出,說明我們加的鎖是可以用的。
四,總結
在這里我們實現的是一個可重入的,不公平,利用自旋來阻塞的一個鎖,后續繼續深入。
總結
以上是生活随笔為你收集整理的AQS理解之二,自己设计一个锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AQS理解之一,基础知识——LockSu
- 下一篇: AQS理解之三,由刚才写的锁转变成一个公