成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java多線程之內置鎖與顯示鎖

開發 后端
Java中具有通過Synchronized實現的內置鎖,和ReentrantLock實現的顯示鎖,這兩種鎖各有各的好處,算是互有補充,今天就來做一個總結。

[[192661]]

Java中具有通過Synchronized實現的內置鎖,和ReentrantLock實現的顯示鎖,這兩種鎖各有各的好處,算是互有補充,今天就來做一個總結。

Synchronized

內置鎖獲得鎖和釋放鎖是隱式的,進入synchronized修飾的代碼就獲得鎖,走出相應的代碼就釋放鎖。

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

通信

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

wait()方法會立即釋放當前鎖,并進入等待狀態,等待到相應的notify并重新獲得鎖過后才能繼續執行;notify()不會立刻立刻釋放鎖,必須要等notify()所在線程執行完synchronized塊中的所有代碼才會釋放。用如下代碼來進行驗證:

  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.  

運行結果

  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 

可見讀線程開始運行,開始wait過后,寫線程才獲得鎖;寫線程走出同步塊而不是notify過后,讀線程才wait結束,亦即獲得鎖。所以notify不會釋放鎖,wait會釋放鎖。值得一提的是,notifyall()會通知等待隊列中的所有線程。

編碼

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

  1. synchronized(object){ 
  2.  
  3.  

靈活性

內置鎖在進入同步塊時,采取的是***等待的策略,一旦開始等待,就既不能中斷也不能取消,容易產生饑餓與死鎖的問題

在線程調用notify方法時,會隨機選擇相應對象的等待隊列的一個線程將其喚醒,而不是按照FIFO的方式,如果有強烈的公平性要求,比如FIFO就無法滿足

性能

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

ReentrantLock

ReentrantLock是顯示鎖,需要顯示進行 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()才能創建一個Condition。從上面的代碼可以看出,Synchronized能實現的通信方式,Condition都可以實現,功能類似的代碼寫在同一行中。而Condition的優秀之處在于它可以為多個線程間建立不同的Condition,比如對象的讀/寫Condition,隊列的空/滿Condition,在JDK源碼中的ArrayBlockingQueue中就使用了這個特性:

  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要復雜一些,而且一定要記得在finally中釋放鎖而不是其他地方,這樣才能保證即使出了異常也能釋放鎖。

靈活性

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

ReentrantLock可以成為公平鎖(非默認的),所謂公平鎖就是鎖的等待隊列的FIFO,不過公平鎖會帶來性能消耗,如果不是必須的不建議使用。這和CPU對指令進行重排序的理由是相似的,如果強行的按照代碼的書寫順序來執行指令,就會浪費許多時鐘周期,達不到***利用率

性能

雖然Synchronized和標準的ReentrantLock性能差別不大,但是ReentrantLock還提供了一種非互斥的讀寫鎖,

也就是不強制每次最多只有一個線程能持有鎖,它會避免“讀/寫”沖突,“寫/寫”沖突,但是不會排除“讀/讀”沖突,

因為“讀/讀”并不影響數據的完整性,所以可以多個讀線程同時持有鎖,這樣在讀寫比較高的情況下,性能會有很大的提升。

下面用兩種鎖分別實現的線程安全的linkedlist:

  1. class RWLockList {//讀寫鎖 
  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.  

 讀寫鎖測試代碼:

  1. List list = new LinkedList();for (int i=0;i<10000;i++){ 
  2.     list.add(i); 
  3. RWLockList rwLockList = new RWLockList(list);//初始化數據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"); 

 同步鎖測試代碼:

  1. List list = new LinkedList();for (int i=0;i<10000;i++){ 
  2.     list.add(i); 
  3. SyncList syncList = new SyncList(list);//初始化數據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"); 

 結果:

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

可見讀寫鎖的確是優于純碎的互斥鎖

總結

內置鎖***優點是簡潔易用,顯示鎖***優點是功能豐富,所以能用內置鎖就用內置鎖,在內置鎖功能不能滿足之時在考慮顯示鎖。

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

責任編輯:龐桂玉 來源: 程序源
相關推薦

2017-05-08 11:46:15

Java多線程

2018-10-25 15:55:44

Java多線程鎖優化

2021-12-26 18:22:30

Java線程多線程

2020-07-06 08:03:32

Java悲觀鎖樂觀鎖

2023-06-09 07:59:37

多線程編程鎖機制

2024-10-14 16:25:59

C#線程鎖代碼

2022-06-15 07:32:35

Lock線程Java

2009-12-08 10:07:29

2023-10-08 09:34:11

Java編程

2010-03-16 17:16:38

Java多線程

2017-11-17 15:57:09

Java多線程并發模型

2024-06-24 08:10:00

C++互斥鎖

2011-01-26 10:53:48

JavaScriptWeb

2010-03-16 17:39:36

Java多線程鎖

2024-08-28 08:00:00

2024-06-28 08:45:58

2020-08-26 08:59:58

Linux線程互斥鎖

2011-06-22 16:02:37

Qt 多線程 重入

2019-01-04 11:18:35

獨享鎖共享鎖非公平鎖

2022-02-14 15:07:48

進程FileChanne線程
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲精品白浆高清久久久久久 | 精品一区在线 | 午夜久草 | 国产日韩欧美中文字幕 | av福利网站 | 99精品在线免费观看 | 日本黄色片免费在线观看 | 999精品视频 | 国产成人自拍一区 | 日日日干干干 | 羞羞视频在线观看网站 | 日韩在线观看 | 日韩三级在线 | 日韩欧美精品在线 | 美国一级片在线观看 | 97人人爱 | 久久精品一级 | 久久国产区 | 99国内精品久久久久久久 | 亚洲精品一区中文字幕乱码 | 中文字幕日韩一区 | 黑人巨大精品欧美一区二区一视频 | 国产视频福利一区 | 一区二区三区影院 | 日韩在线不卡视频 | 视频一区二区三区在线观看 | av一级毛片 | 精品国产乱码久久久久久图片 | 黄色一级片视频 | 青青草华人在线视频 | 日韩视频一区在线观看 | 色婷婷狠狠 | 国产精品久久久久久久久久久免费看 | 欧美成人专区 | 在线免费激情视频 | 日韩精品免费一区二区在线观看 | 天天干人人 | 久久亚洲欧美日韩精品专区 | 精品免费国产视频 | 亚洲国产精品99久久久久久久久 | 岛国av一区二区三区 |