<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## Java專題十三(2):線程安全與同步 [TOC] 多個線程訪問共享資源和可變資源時,由于線程執行的隨機性,可能導致程序出現錯誤的結果 > 假設我們要實現一個視頻網站在線人數統計功能,在每個客戶端登錄網站時,統計在線人數,通常用一個變量count代表人數,用戶上線后,count++ ```java class Online{ int count; public Online(){ this.count = 0; } public void login(){ count++; } } ``` 假設目前在線人數count是10,甲登錄網站,網站后臺讀取到count值為10(count++分為三步:讀取-修改-寫入),還沒來得及修改,這時乙也在登錄,后臺讀取到count值也為10,最終甲、乙登錄完成后,count變為了11,正確結果本來應該是12的 ### 原子變量 java.util.concurrent.atomic包中有很多原子變量,用于對數據進行原子操作 如對于上面的問題,可以用AtomicInteger原子變量的incrementAndGet()來實現正確操作 ### synchronized關鍵字 - 方法同步 ```java public synchronized void login(){ count++; } ``` - 代碼塊同步 靜態方法內代碼:`synchronized(Online.class)` 非靜態方法內代碼:`synchronized(this)` ```java public void login(){ synchronized(this){ count++; } } ``` ### 鎖機制 位于`java.util.concurrent.locks`包中 ~~~ public interface Lock { void lock(); boolean tryLock(); boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock(); Condition newCondition(); } ~~~ | 鎖 | 說明 | | --- | --- | | ReentrantLock | 可重入互斥鎖 | | ReentrantReadWriteLock | 可重入讀寫鎖 | - ReentrantLock ~~~ class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } }} ~~~ - ReentrantReadWriteLock ```java class CachedData { Object data; volatile boolean cacheValid; final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); void processCachedData() { rwl.readLock().lock(); if (!cacheValid) { // Must release read lock before acquiring write lock rwl.readLock().unlock(); rwl.writeLock().lock(); try { // Recheck state because another thread might have // acquired write lock and changed state before we did. if (!cacheValid) { data = ... cacheValid = true; } // Downgrade by acquiring read lock before releasing write lock rwl.readLock().lock(); } finally { rwl.writeLock().unlock(); // Unlock write, still hold read } } try { use(data); } finally { rwl.readLock().unlock(); } } }} ``` #### 一些鎖的概念 可重入鎖:同一線程在方法獲取鎖的時候,在進入前面方法內部調用其它方法會自動獲取鎖 公平鎖:按照線程鎖申請后順序來獲取鎖 非公平鎖:不一定按照線程鎖申請先后順序來獲取鎖 樂觀鎖:樂觀地認為其他人讀數據時都不會修改數據,不會上鎖 悲觀鎖:悲觀地認為其他人讀數據時都會修改數據,會上鎖,別人只能等待它釋放鎖 共享鎖:同一時刻可以被多個線程擁有 獨占鎖:同一時刻只能被一個線程擁有 ### 計數信號量 `java.util.concurrent.Semaphore` 通常一個信號量維持著一個許可證的集合,`acquire`方法會申請許可證`permit`,讓線程阻塞直到許可證是空的,而`release`方法會釋放一個許可證 > 假設現在有一個類使用信號量去實現資源池,生產者消費者模式線程同步 ~~~ public class Pool<E> { private final E[] items; private final Semaphore availableItems; private final Semaphore availableSpaces; private int putPosition = 0, takePosition = 0; Pool(int capacity) { availableItems = new Semaphore(0); availableSpaces = new Semaphore(capacity); items = (E[]) new Object[capacity]; } boolean isEmpty(){ return availableItems.availablePermits() == 0; } boolean isFull(){ return availableSpaces.availablePermits() == 0; } public void put(E x) throws InterruptedException { availableSpaces.acquire(); doInsert(x); availableItems.release(); } public E take() throws InterruptedException { availableItems.acquire(); E item = doExtract(); availableSpaces.release(); return item; } private synchronized void doInsert(E x) { int i = putPosition; items[i] = x; putPosition = (++i == items.length) ? 0 : i; } private synchronized E doExtract() { int i = takePosition; E x = items[i]; items[i] = null; takePosition = (++i == items.length) ? 0 : i; return x; } } ~~~ 首先定義2個信號量`Semaphore`: - `availableItems`代表可用資源數,數值初始化為`0` - `availableSpaces`可用空間數,數值初始化為`capacity` 生產消費操作實現方法: - 從池中取出資源(`take`): - 判斷是否有可用資源,調用`availableItems.acquire()`查詢`availableItems`許可證,該方法會阻塞直到池中有可用資源 - 存入資源(`doExtract方法`) - 釋放`availableSpaces.release()`釋放許可證,表示池中多了一個可用的空間,可以用來存放新的資源 - 放入資源至池中(`put`): - 判斷是否有可用空間,調用`availableSpaces.acquire()`查詢`availableSpaces`許可證,該方法會阻塞直到池中有可用空間 - 取出資源(`doInsert方法`) - 釋放`availableItems.release()`釋放許可證,表示池中多了一個可用資源,可以來訪問該資源
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看