咱們知道List的實現類ArrayList,LinkedList都是非線程安全的,Vector類經過用synchronized修飾方法保證了List的多線程非安全問題,可是有個缺點:讀寫同步,效率低下。因而就出現了CopyOnWriteArrayList,它經過寫時複製數組實現了讀寫分離,提升了多線程對List讀的效率,適合多讀少些的狀況。同理:咱們知道ReentrantLock,它是一把獨佔的鎖,是用來控制線程同步的,若是咱們用ReentrantLock來實現ArrayList安全,可否達到CopyOnWriteArrayList一樣的效果呢?
java
import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author :jiaolian * @date :Created in 2021-01-26 15:49 * @description:ReentrantReadWriteLock多讀少寫的場景 * @modified By: * 公衆號:叫練 */ public class MultReadTest { private static class MyList { private final ReentrantReadWriteLock REENTRANT_READ_WRITE_LOCK = new ReentrantReadWriteLock(); private final ReentrantReadWriteLock.WriteLock WRITE_LOCK = REENTRANT_READ_WRITE_LOCK.writeLock(); private final ReentrantReadWriteLock.ReadLock READ_LOCK = REENTRANT_READ_WRITE_LOCK.readLock(); private List<String> list = new ArrayList(); //讀list public void readList() { try { READ_LOCK.lock(); Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+":"+list.size()); } catch (InterruptedException e) { e.printStackTrace(); } finally { READ_LOCK.unlock(); } } //寫list public void writeList() { try { WRITE_LOCK.lock(); Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+":新增1個元素"); list.add("叫練【公衆號】"); } catch (InterruptedException e) { e.printStackTrace(); } finally { WRITE_LOCK.unlock(); } } } public static void main(String[] args) { MyList myList = new MyList(); //讀寫鎖適合多讀少寫狀況 //新建10個讀線程,1個寫線程 new Thread(()->{myList.writeList();},"寫線程").start(); for (int i=0; i<10; i++) { new Thread(()->{myList.readList();},"讀線程"+(i+1)).start(); } } }
上面案例咱們用ReentrantReadWriteLock實現了CopyOnWriteArrayList,主線程新建了1個寫線程寫list,10個讀線程讀list,程序一共花費2執行完畢,若是用Vector須要花費11秒。在多線程的狀況下,經過讀寫鎖操做List,提升了List的讀效率,在List讀的部分,線程是共享的,在對List寫的過程當中,在對寫的線程是同步的,所以咱們能夠得出一個結論:讀寫鎖是讀讀共享,讀寫同步!面試
如上圖,咱們簡單的梳理下獨佔獲取鎖流程。數組
如上圖,咱們簡單的梳理下共享鎖獲取鎖流程。安全
咱們說讀寫互斥,但同一個線程中,先寫後讀也是容許的,咱們稱之爲鎖降級。在面試中共享鎖面試頻率也比較高,方便理解咱們舉個簡單的案例說明下。多線程
import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author :jiaolian * @date :Created in 2021-01-28 15:44 * @description:ReentrantReadWriteLock讀寫鎖降級測試 * @modified By: * 公衆號:叫練 */ public class WriteLockLowerTest { private static final ReentrantReadWriteLock REENTRANT_READ_WRITE_LOCK = new ReentrantReadWriteLock(); private static final ReentrantReadWriteLock.WriteLock WRITE_LOCK = REENTRANT_READ_WRITE_LOCK.writeLock(); private static final ReentrantReadWriteLock.ReadLock READ_LOCK = REENTRANT_READ_WRITE_LOCK.readLock(); public static void main(String[] args) { try { WRITE_LOCK.lock(); System.out.println("獲取寫鎖"); READ_LOCK.lock(); System.out.println("獲取讀鎖"); } finally { READ_LOCK.unlock(); System.out.println("釋放寫鎖"); WRITE_LOCK.unlock(); System.out.println("釋放讀鎖"); } } }
如上述代碼:程序能夠運行完畢,說明鎖能夠降級。另外說一句,上面的程序先獲取讀鎖再獲取寫鎖,程序是會阻塞的,爲何呢?歡迎小夥伴在留言區寫下評論!ide
今天咱們用通俗易懂的文字描述了ReentrantReadWriteLock讀寫鎖。喜歡的請點贊加評論哦!點關注,不迷路,我是叫練【公衆號】,邊叫邊練。期待咱們下次再見!測試