偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Java多線(xiàn)程之內(nèi)置鎖與顯示鎖

開(kāi)發(fā) 后端
Java中具有通過(guò)Synchronized實(shí)現(xiàn)的內(nèi)置鎖,和ReentrantLock實(shí)現(xiàn)的顯示鎖,這兩種鎖各有各的好處,算是互有補(bǔ)充,今天就來(lái)做一個(gè)總結(jié)。

[[192661]]

Java中具有通過(guò)Synchronized實(shí)現(xiàn)的內(nèi)置鎖,和ReentrantLock實(shí)現(xiàn)的顯示鎖,這兩種鎖各有各的好處,算是互有補(bǔ)充,今天就來(lái)做一個(gè)總結(jié)。

Synchronized

內(nèi)置鎖獲得鎖和釋放鎖是隱式的,進(jìn)入synchronized修飾的代碼就獲得鎖,走出相應(yīng)的代碼就釋放鎖。

  1. synchronized(list){ //獲得鎖 
  2.  
  3.   list.append(); list.count(); 
  4.  
  5. }//釋放鎖  

通信

與Synchronized配套使用的通信方法通常有wait(),notify()。

wait()方法會(huì)立即釋放當(dāng)前鎖,并進(jìn)入等待狀態(tài),等待到相應(yīng)的notify并重新獲得鎖過(guò)后才能繼續(xù)執(zhí)行;notify()不會(huì)立刻立刻釋放鎖,必須要等notify()所在線(xiàn)程執(zhí)行完synchronized塊中的所有代碼才會(huì)釋放。用如下代碼來(lái)進(jìn)行驗(yàn)證:

  1. public static void main(String[] args){    List list = new LinkedList(); 
  2.     Thread r = new Thread(new ReadList(list)); 
  3.     Thread w = new Thread(new WriteList(list)); 
  4.     r.start(); 
  5.     w.start(); 
  6. }class ReadList implements Runnable{    private List list;    public ReadList(List list){ this.list = list; } 
  7.  
  8.     @Override    public void run(){ 
  9.         System.out.println("ReadList begin at "+System.currentTimeMillis()); 
  10.         synchronized (list){            try { 
  11.                 Thread.sleep(1000); 
  12.                 System.out.println("list.wait() begin at "+System.currentTimeMillis());                list.wait(); 
  13.                 System.out.println("list.wait() end at "+System.currentTimeMillis()); 
  14.             } catch (InterruptedException e) { 
  15.                 e.printStackTrace(); 
  16.             } 
  17.         } 
  18.         System.out.println("ReadList end at "+System.currentTimeMillis()); 
  19.  
  20.     } 
  21. }class WriteList implements Runnable{    private List list;    public WriteList(List list){ this.list = list; } 
  22.  
  23.     @Override    public void run(){ 
  24.         System.out.println("WriteList begin at "+System.currentTimeMillis()); 
  25.         synchronized (list){ 
  26.             System.out.println("get lock at "+System.currentTimeMillis());            list.notify(); 
  27.             System.out.println("list.notify() at "+System.currentTimeMillis());            try { 
  28.                 Thread.sleep(2000); 
  29.             } catch (InterruptedException e) { 
  30.                 e.printStackTrace(); 
  31.             } 
  32.             System.out.println("get out of block at "+System.currentTimeMillis()); 
  33.         } 
  34.         System.out.println("WriteList end at "+System.currentTimeMillis()); 
  35.  
  36.     } 
  37.  

運(yùn)行結(jié)果

  1. ReadList begin at 1493650526582WriteList begin at 1493650526582list.wait() begin at 1493650527584get lock at 1493650527584list.notify() at 1493650527584get out of block at 1493650529584WriteList end at 1493650529584list.wait() end at 1493650529584ReadList end at 1493650529584 

可見(jiàn)讀線(xiàn)程開(kāi)始運(yùn)行,開(kāi)始wait過(guò)后,寫(xiě)線(xiàn)程才獲得鎖;寫(xiě)線(xiàn)程走出同步塊而不是notify過(guò)后,讀線(xiàn)程才wait結(jié)束,亦即獲得鎖。所以notify不會(huì)釋放鎖,wait會(huì)釋放鎖。值得一提的是,notifyall()會(huì)通知等待隊(duì)列中的所有線(xiàn)程。

編碼

編碼模式比較簡(jiǎn)單,單一,不必顯示的獲得鎖,釋放鎖,能降低因粗心忘記釋放鎖的錯(cuò)誤。使用模式如下:

  1. synchronized(object){ 
  2.  
  3.  

靈活性

內(nèi)置鎖在進(jìn)入同步塊時(shí),采取的是***等待的策略,一旦開(kāi)始等待,就既不能中斷也不能取消,容易產(chǎn)生饑餓與死鎖的問(wèn)題

在線(xiàn)程調(diào)用notify方法時(shí),會(huì)隨機(jī)選擇相應(yīng)對(duì)象的等待隊(duì)列的一個(gè)線(xiàn)程將其喚醒,而不是按照FIFO的方式,如果有強(qiáng)烈的公平性要求,比如FIFO就無(wú)法滿(mǎn)足

性能

Synchronized在JDK1.5及之前性能(主要指吞吐率)比較差,擴(kuò)展性也不如ReentrantLock。但是JDK1.6以后,修改了管理內(nèi)置鎖的算法,使得Synchronized和標(biāo)準(zhǔn)的ReentrantLock性能差別不大。

ReentrantLock

ReentrantLock是顯示鎖,需要顯示進(jìn)行 lock 以及 unlock 操作。

通信

與ReentrantLock搭配的通行方式是Condition,如下:

  1. private Lock lock = new ReentrantLock(); 
  2.  
  3. private Condition condition = lock.newCondition(); 
  4.  
  5. condition.await();//this.wait(); condition.signal();//this.notify(); condition.signalAll();//this.notifyAll();  

Condition是被綁定到Lock上的,必須使用lock.newCondition()才能創(chuàng)建一個(gè)Condition。從上面的代碼可以看出,Synchronized能實(shí)現(xiàn)的通信方式,Condition都可以實(shí)現(xiàn),功能類(lèi)似的代碼寫(xiě)在同一行中。而Condition的優(yōu)秀之處在于它可以為多個(gè)線(xiàn)程間建立不同的Condition,比如對(duì)象的讀/寫(xiě)Condition,隊(duì)列的空/滿(mǎn)Condition,在JDK源碼中的ArrayBlockingQueue中就使用了這個(gè)特性:

  1.  public ArrayBlockingQueue(int capacity, boolean fair) {    if (capacity <= 0)        throw new IllegalArgumentException();    this.items = new Object[capacity];    lock = new ReentrantLock(fair); 
  2.     notEmpty = lock.newCondition(); 
  3.     notFull =  lock.newCondition(); 
  4. }public void put(E e) throws InterruptedException { 
  5.     checkNotNull(e); 
  6.     final ReentrantLock lock = this.lock;    lock.lockInterruptibly();    try {        while (count == items.length) 
  7.             notFull.await(); 
  8.         enqueue(e); 
  9.     } finally {        lock.unlock(); 
  10.     } 
  11. }public E take() throws InterruptedException { 
  12.     final ReentrantLock lock = this.lock;    lock.lockInterruptibly();    try {        while (count == 0) 
  13.             notEmpty.await();        return dequeue(); 
  14.     } finally {        lock.unlock(); 
  15.     } 
  16. }private void enqueue(E x) {    // assert lock.getHoldCount() == 1; 
  17.     // assert items[putIndex] == null
  18.     final Object[] items = this.items; 
  19.     items[putIndex] = x;    if (++putIndex == items.length) 
  20.         putIndex = 0; 
  21.     count++; 
  22.     notEmpty.signal(); 
  23. }private E dequeue() {    // assert lock.getHoldCount() == 1; 
  24.     // assert items[takeIndex] != null
  25.     final Object[] items = this.items; 
  26.     @SuppressWarnings("unchecked"
  27.     E x = (E) items[takeIndex]; 
  28.     items[takeIndex] = null;    if (++takeIndex == items.length) 
  29.         takeIndex = 0; 
  30.     count--;    if (itrs != null) 
  31.         itrs.elementDequeued(); 
  32.     notFull.signal();    return x; 
  33.  

編碼

  1. Lock lock = new ReentrantLock();lock.lock();try{ 
  2.  
  3. }finally{    lock.unlock(); 
  4.  

相比于Synchronized要復(fù)雜一些,而且一定要記得在finally中釋放鎖而不是其他地方,這樣才能保證即使出了異常也能釋放鎖。

靈活性

lock.lockInterruptibly() 可以使得線(xiàn)程在等待鎖是支持響應(yīng)中斷;lock.tryLock() 可以使得線(xiàn)程在等待一段時(shí)間過(guò)后如果還未獲得鎖就停止等待而非一直等待。有了這兩種機(jī)制就可以更好的制定獲得鎖的重試機(jī)制,而非盲目一直等待,可以更好的避免饑餓和死鎖問(wèn)題

ReentrantLock可以成為公平鎖(非默認(rèn)的),所謂公平鎖就是鎖的等待隊(duì)列的FIFO,不過(guò)公平鎖會(huì)帶來(lái)性能消耗,如果不是必須的不建議使用。這和CPU對(duì)指令進(jìn)行重排序的理由是相似的,如果強(qiáng)行的按照代碼的書(shū)寫(xiě)順序來(lái)執(zhí)行指令,就會(huì)浪費(fèi)許多時(shí)鐘周期,達(dá)不到***利用率

性能

雖然Synchronized和標(biāo)準(zhǔn)的ReentrantLock性能差別不大,但是ReentrantLock還提供了一種非互斥的讀寫(xiě)鎖,

也就是不強(qiáng)制每次最多只有一個(gè)線(xiàn)程能持有鎖,它會(huì)避免“讀/寫(xiě)”沖突,“寫(xiě)/寫(xiě)”沖突,但是不會(huì)排除“讀/讀”沖突,

因?yàn)?ldquo;讀/讀”并不影響數(shù)據(jù)的完整性,所以可以多個(gè)讀線(xiàn)程同時(shí)持有鎖,這樣在讀寫(xiě)比較高的情況下,性能會(huì)有很大的提升。

下面用兩種鎖分別實(shí)現(xiàn)的線(xiàn)程安全的linkedlist:

  1. class RWLockList {//讀寫(xiě)鎖 
  2.  
  3.     private List list;    private final ReadWriteLock lock = new ReentrantReadWriteLock();    private final Lock readLock = lock.readLock();    private final Lock writeLock = lock.writeLock();    public RWLockList(List list){this.list = list;}    public int get(int k) { 
  4.         readLock.lock();        try {            return (int)list.get(k); 
  5.         } finally { 
  6.             readLock.unlock(); 
  7.         } 
  8.     }    public void put(int value) { 
  9.         writeLock.lock();        try { 
  10.             list.add(value); 
  11.         } finally { 
  12.             writeLock.unlock(); 
  13.         } 
  14.     } 
  15. }class SyncList  {    private List list;    public SyncList(List list){this.list = list;}    public synchronized int  get(int k){        return (int)list.get(k); 
  16.     }    public synchronized void put(int value){ 
  17.         list.add(value); 
  18.     } 
  19.  

 讀寫(xiě)鎖測(cè)試代碼:

  1. List list = new LinkedList();for (int i=0;i<10000;i++){ 
  2.     list.add(i); 
  3. RWLockList rwLockList = new RWLockList(list);//初始化數(shù)據(jù)Thread writer = new Thread(new Runnable() { 
  4.     @Override    public void run() {        for (int i=0;i<10000;i++){ 
  5.             rwLockList.put(i); 
  6.         } 
  7.     } 
  8. }); 
  9. Thread reader1 = new Thread(new Runnable() { 
  10.     @Override    public void run() {        for (int i=0;i<10000;i++){ 
  11.             rwLockList.get(i); 
  12.         } 
  13.     } 
  14. }); 
  15. Thread reader2 = new Thread(new Runnable() { 
  16.     @Override    public void run() {        for (int i=0;i<10000;i++){ 
  17.             rwLockList.get(i); 
  18.         } 
  19.     } 
  20. });long begin = System.currentTimeMillis(); 
  21. writer.start();reader1.start();reader2.start();try { 
  22.     writer.join(); 
  23.     reader1.join(); 
  24.     reader2.join(); 
  25. } catch (InterruptedException e) { 
  26.     e.printStackTrace(); 
  27. System.out.println("RWLockList take "+(System.currentTimeMillis()-begin) + "ms"); 

 同步鎖測(cè)試代碼:

  1. List list = new LinkedList();for (int i=0;i<10000;i++){ 
  2.     list.add(i); 
  3. SyncList syncList = new SyncList(list);//初始化數(shù)據(jù)Thread writerS = new Thread(new Runnable() { 
  4.     @Override    public void run() {        for (int i=0;i<10000;i++){ 
  5.             syncList.put(i); 
  6.         } 
  7.     } 
  8. }); 
  9. Thread reader1S = new Thread(new Runnable() { 
  10.     @Override    public void run() {        for (int i=0;i<10000;i++){ 
  11.             syncList.get(i); 
  12.         } 
  13.     } 
  14. }); 
  15. Thread reader2S = new Thread(new Runnable() { 
  16.     @Override    public void run() {        for (int i=0;i<10000;i++){ 
  17.             syncList.get(i); 
  18.         } 
  19.     } 
  20. });long begin1 = System.currentTimeMillis(); 
  21. writerS.start();reader1S.start();reader2S.start();try { 
  22.     writerS.join(); 
  23.     reader1S.join(); 
  24.     reader2S.join(); 
  25. } catch (InterruptedException e) { 
  26.     e.printStackTrace(); 
  27. System.out.println("SyncList take "+(System.currentTimeMillis()-begin1) + "ms"); 

 結(jié)果:

  1. RWLockList take 248msRWLockList take 255msRWLockList take 249msRWLockList take 224msSyncList take 351msSyncList take 367msSyncList take 315msSyncList take 323ms 

可見(jiàn)讀寫(xiě)鎖的確是優(yōu)于純碎的互斥鎖

總結(jié)

內(nèi)置鎖***優(yōu)點(diǎn)是簡(jiǎn)潔易用,顯示鎖***優(yōu)點(diǎn)是功能豐富,所以能用內(nèi)置鎖就用內(nèi)置鎖,在內(nèi)置鎖功能不能滿(mǎn)足之時(shí)在考慮顯示鎖。

關(guān)于兩種鎖,目前接觸到的就是這么多,總結(jié)不到位之處,歡迎拍磚。 

責(zé)任編輯:龐桂玉 來(lái)源: 程序源
相關(guān)推薦

2017-05-08 11:46:15

Java多線(xiàn)程

2018-10-25 15:55:44

Java多線(xiàn)程鎖優(yōu)化

2021-12-26 18:22:30

Java線(xiàn)程多線(xiàn)程

2023-06-09 07:59:37

多線(xiàn)程編程鎖機(jī)制

2024-10-14 16:25:59

C#線(xiàn)程鎖代碼

2020-07-06 08:03:32

Java悲觀(guān)鎖樂(lè)觀(guān)鎖

2022-06-15 07:32:35

Lock線(xiàn)程Java

2009-12-08 10:07:29

2023-10-08 09:34:11

Java編程

2010-03-16 17:16:38

Java多線(xiàn)程

2017-11-17 15:57:09

Java多線(xiàn)程并發(fā)模型

2024-06-24 08:10:00

C++互斥鎖

2011-01-26 10:53:48

JavaScriptWeb類(lèi)

2019-01-04 11:18:35

獨(dú)享鎖共享鎖非公平鎖

2020-08-26 08:59:58

Linux線(xiàn)程互斥鎖

2011-06-22 16:02:37

Qt 多線(xiàn)程 重入

2010-03-16 17:39:36

Java多線(xiàn)程鎖

2024-08-28 08:00:00

2024-06-28 08:45:58

2022-02-14 15:07:48

進(jìn)程FileChanne線(xiàn)程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)