Java高併發24-使用自定義鎖生成一個消費模型

1、使用自定義鎖實現生成--消費模型

下面咱們使用上節自定義的鎖實現一個簡單的生產--消費模型,代碼以下:

package com.ruigege.LockSourceAnalysis6;

import java.util.Queue;
import java.util.concurrent.locks.Condition;

public class Test {
 final static NonReentrantLock lock = new NonReentrantLock();
 final static Condition notFull = lock.newCondition();
 final static Condition notEmpty = lock.newCondition();
 
 final static Queue<String> queue = new LinkedBlockingQueue<String>();
 final static int queueSize = 10;
 
 public static void main(String[] args) {
  Thread producer = new Thread(new Runnable() {
   public void run() {
    // 獲取獨佔鎖
    lock.lock();
    try {
     // (1)若是隊列滿了,則等待
     while(queue.size() == queueSize) {
      notEmpty.await();
     }
     // (2)添加元素到隊列
     queue.add("ele");
     
     // (3)喚醒消費線程
     notFull.signalAll();
    }catch(Exception e) {
     e.printStackTrace();
    }finally {
     // 釋放鎖
     lock.unlock();
    }
   }
  });
  
  Thread consumer = new Thread(new Runnable() {
   public void run() {
    // 獲取獨佔鎖
    lock.lock();
    try {
     // 隊列空,則等待
     while(0 == queue.size()) {
      notFull.await();
     }
     // 消費一個元素
     String ele = queue.poll();
     // 喚醒生產線程
     notEmpty.signalAll();
    }catch(Exception e) {
     e.printStackTrace();
    }finally {
     // 釋放鎖
     lock.unlock();
    }
   }
  });
  // 啓動線程
  producer.start();
  consumer.start();
 }

}

  • 如上代碼首先建立了一個NonReentrantLock的一個對象lock,而後調用lock.newCondition建立了兩個條件變量,用來進行生產者和消費者線程之間的同步。
  • 在main函數中,首先建立了producer生產線程,在線程內部首先調用lock.lock()獲取獨佔鎖,而後判斷當前隊列是否已經滿了,若是滿了則調用notEmpty.await()阻塞掛起當前線程,須要注意的是,這裏使用了while而不是if是爲了不虛假喚醒,若是隊列不滿則直接向隊列裏面添加元素,而後調用notFull.signalAll()喚醒全部由於消費元素而被i阻塞的消費線程,最後釋放獲取的鎖。

二.使用自定義鎖實現一個消費模型

package com.ruigege.LockSourceAnalysis6;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class NonReentrantLockME implements Lock,java.io.Serializable{
 // 內部幫助類
 private static class Sync extends AbstractQueueSynchronizer {
  // 是否鎖已經被持有
  protected boolean isHeldExclusively() {
   return getState() == 1;
  }
  
  // 若是state爲0,則嘗試獲取鎖
  public boolean tryAcquire(int acquires) {
   assert acquires == 1;
   if(compareAndSetState(0,1)) {
    setExclusiveOwnerThread(Thread.currentThread());
    return true;
   }
   return false;
  }
  
  // 嘗試釋放鎖,設置state爲0
  protected boolean tryRelease(int release) {
   assert releases == 1;
   if(getState() == 0) {
    throw new IllegalMonitorStateException();
   }
   setExclusiveOwnerThread(null);
   setState(0);
   return true;
  }
  
  // 提供條件變量接口
  Condition newConditon() {
   return new ConditionObject();
  }
 }
 
 // 建立一個Sync來作具體的工做
 private final Sync sync = new Sync();
 
 public void lock() {
  sync.acquire(1);
 }
 
 public boolean tryLock() {
  return sync.tryAcquire(1);
 }
 
 public void unlock() {
  sync.release(1);
  
 }
 public Condition newCondition() {
  return sync.newConditon();
 }
 
 
 public boolean isLocked() {
  return sync.isHeldExclusively();
 }
 
 public void lockInterruptibly() throws InterruptedException {
  sync.acquireInterruptibly(1);
 }

 public boolean tryLock(long timeout,TimeUnit unit) throws InterruptedException {
  return sync.tryAcquireNanos(1,unit.toNanos(timeout));
 }
}

  • 使用NonReentrantLock建立一個實例,而後調用newCondition方法來生成兩個條件變量來進行生產者和消費者線程之間的同步。
  • 在main函數中,首先建立了producer生產線程,在線程內部先獲取了獨佔鎖,而後看一下隊列是否滿了,若是滿了,那就阻塞當前線程,若是沒有滿直接在隊列中加入隊列中,這裏使用的while循環而不是使用if語句,這是爲了不虛假喚醒。而後調用notFull.sinalAll()喚醒全部由於消費元素而被阻塞的消費線程,最後釋放了鎖。
  • 在main函數中建立了consumer線程,先獲取獨佔鎖,先判斷隊列有沒有元素,若是沒有元素,那麼就先掛起當前線程,這裏使用了while是爲了不虛假喚醒,若是隊列中不爲空,那麼就拿出一個元素,而後喚醒由於隊列滿而被阻塞的生產線程,最後釋放獲取的鎖。

3、源碼:

相關文章
相關標籤/搜索