獨占鎖(排他鎖/寫鎖/X鎖/行級):指該鎖一次只能被一個線程鎖持有,只允許該線程寫與讀,不允許其他線程加任何鎖進行讀和寫,ReentrantLock和sync而言都是獨占鎖。
共享鎖(讀鎖/S鎖/表級):指該鎖可被多個線程所持有,直到釋放所有S鎖才可以獲取排他鎖。
讀寫鎖:ReentrantReadWriteLock,表示以上兩個鎖
讀寫鎖特點:
- 讀-讀能共享
- 讀-寫互斥
- 寫-讀互斥
- 寫-寫互斥
LockSupport
二元信號量做的線程阻塞工具類,要注意的是,這個信號量最多只能加到1,可以讓線程在任意位置阻塞,當然阻塞之后肯定得有喚醒的方法。有park停車和unpark方法,park和unpark可以實現類似wait和notify的功能,不會出現死鎖的情況,底層其實都是依賴Unsafe實現。
面試題:兩個線程交替輸出
注意,unpark函數可以先於park調用。比如線程B調用unpark函數,給線程A發了一個“許可”,那么當線程A調用park時,它發現已經有“許可”了,那么它會馬上再繼續運行。“許可”是一次性的。不像object.wait和notify有先后調用順序,notify/notyfAll必須在wait之后執行,lockSuppoort不再需要關心對方的狀態。, 另外,和wait方法不同,執行park進入休眠后並不會釋放持有的鎖。park方法不會拋出InterruptedException,但是它也會響應中斷 https://blog.csdn.net/u013332124/article/details/84647915
線程的Thread.join 含義: 當前線程A等待thread線程終止之后才能從thread.join()返回
ReentrantReadWriteLock 讀寫鎖詳解
現實中有這樣一種場景:對共享資源有讀和寫的操作,且寫操作沒有讀操作那么頻繁。在沒有寫操作的時候,多個線程同時讀一個資源沒有任何問題,所以應該允許多個線程同時讀取共享資源;但是如果一個線程想去寫這些共享資源,就不應該允許其他線程對該資源進行讀和寫的操作了。
針對這種場景,JAVA的並發包提供了ReentrantReadWriteLock讀寫鎖,它表示兩個鎖,一個是讀操作相關的鎖,稱為共享鎖;一個是寫相關的鎖,稱為排他鎖
public class MyTask { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read() { try { lock.readLock().lock(); System.out.println(Thread.currentThread().getName() + " start"); Thread.sleep(10000); System.out.println(Thread.currentThread().getName() + " end"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.readLock().unlock(); } } public void write() { try { lock.writeLock().lock(); System.out.println(Thread.currentThread().getName() + " start"); Thread.sleep(10000); System.out.println(Thread.currentThread().getName() + " end"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.writeLock().unlock(); } } } public class ReadReadTest { public static void main(String[] args) { final MyTask myTask = new MyTask(); Thread t1 = new Thread(new Runnable() { @Override public void run() { myTask.read(); } }); t1.setName("t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { myTask.write(); } }); t2.setName("t2"); t1.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } t2.start(); } }