關(guān)于網(wǎng)站建設(shè)與發(fā)布的書籍怎樣做一個網(wǎng)頁
1 讀寫鎖(ReadWriteLock)
📌 要點(diǎn)
實(shí)現(xiàn)類:ReentrantReadWirteLock
通過讀寫鎖實(shí)現(xiàn)更細(xì)粒度的控制,當(dāng)然通過Synchronized和Lock鎖也能達(dá)到目的,不過他們會在寫入和讀取操作都給加鎖,影響性能;
讀寫鎖在加鎖同時,給讀取操作進(jìn)行優(yōu)化,簡單來說性能更高;
讀寫鎖中,讀鎖是共享鎖,多個線程可以同時占有;寫鎖是獨(dú)占鎖,一次只能被一個線程占有。
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadWriteLockDemo {public static void main(String[] args) {MyCache myCache = new MyCache();//寫入for (int i = 0; i < 5; i++) {final int temp = i;new Thread(()->{myCache.put(temp+"",temp+"");},String.valueOf(i)).start();}//讀取for (int i = 0; i < 5; i++) {final int temp = i;new Thread(()->{myCache.get(temp+"");},String.valueOf(i)).start();}}
}//自定義緩存
class MyCache{private volatile Map<String,Object> map = new HashMap<>();//讀寫鎖,更細(xì)粒度的控制private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();//存、寫入的時候,只希望同時只有一個線程寫public void put(String key,Object value){readWriteLock.writeLock().lock();try {System.out.println(Thread.currentThread().getName()+"寫入"+key);map.put(key,value);System.out.println(Thread.currentThread().getName()+"寫入OK");} catch (Exception e) {e.printStackTrace();} finally {readWriteLock.writeLock().unlock();}}//取、讀,所有人都可以讀public void get(String key){readWriteLock.readLock().lock();try {System.out.println(Thread.currentThread().getName()+"讀取"+key);map.get(key);System.out.println(Thread.currentThread().getName()+"讀取OK");} catch (Exception e) {e.printStackTrace();} finally {readWriteLock.readLock().unlock();}}
}
控制臺輸出:

2 阻塞隊(duì)列(BlockingQueue)
阻塞隊(duì)列(BlockingQueue) 是一個支持兩個附加操作的隊(duì)列。這兩個附加的操作是:在隊(duì)列為空時,獲取元素的線程會等待隊(duì)列變?yōu)榉强?。?dāng)隊(duì)列滿時,存儲元素的線程會等待隊(duì)列可用。
📌 常用實(shí)現(xiàn)類

📌 UML相關(guān)圖

📌 四組API
方式 | 拋出異常 | 不會拋異常,有返回值 | 阻塞等待 | 超時等待 |
添加操作 | add() | offer()供應(yīng) | put() | offer(E e, long timeout,TimeUnit unit) |
移除操作 | remove() | poll()獲得 | take() | poll(long timeout, TimeUnit unit) |
判斷隊(duì)列首部 | element() | peek()偷看,偷窺 |
📌 代碼舉例
public class BlockingQueueDemo {public static void main(String[] args) throws InterruptedException {//隊(duì)列的大小ArrayBlockingQueue queue = new ArrayBlockingQueue(3);System.out.println(queue.offer("A"));System.out.println(queue.offer("B"));System.out.println(queue.offer("C"));System.out.println(queue.offer("D",2, TimeUnit.SECONDS));System.out.println("------------------------");System.out.println(queue.poll());System.out.println(queue.poll());System.out.println(queue.poll());System.out.println(queue.poll());}
控制臺輸出:

3 同步隊(duì)列(SynchronousQueue)
簡單來說,SynchronousQueue是一個沒有數(shù)據(jù)緩沖的阻塞隊(duì)列,它是實(shí)現(xiàn)AbstractQueue接口的。
SynchronousQueue容量為0,生產(chǎn)者線程插入數(shù)據(jù)(put)必須等待消費(fèi)者的移除數(shù)據(jù)(take),反之亦然,也就是說同步隊(duì)列的插入和移除必須是同步的。
public class SynchronousQueueDemo {public static void main(String[] args) throws InterruptedException {SynchronousQueue<String> queue = new SynchronousQueue<>();//同步隊(duì)列new Thread(()->{for (int i = 1; i <= 3; i++) {try {queue.put(String.valueOf(i));System.out.println(Thread.currentThread().getName()+"put "+i);} catch (InterruptedException e) {e.printStackTrace();}}}).start();new Thread(()->{for (int i = 1; i <= 3; i++) {try {TimeUnit.SECONDS.sleep(1);System.out.println(Thread.currentThread().getName()+"take "+queue.take());} catch (InterruptedException e) {e.printStackTrace();}}}).start();}
}
控制臺輸出:

📢 可以看到put和take是伴隨的,同時執(zhí)行順序非固定,說明阻塞隊(duì)列里邊其實(shí)不存元素。