Java-Reentrantlock

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

//條件:Condition 為Lock增長條件,當滿足條件時,作什麼事情,如枷鎖或解鎖。等待喚醒
public class TestContaniner<T> {
	private final LinkedList<T> list = new LinkedList<>();
	private final int MAX = 10;
	private int count = 0;

	private Lock lock = new ReentrantLock();
	private Condition product = lock.newCondition();
	private Condition consumer = lock.newCondition();

	public int getCount() {
		return count;
	}

	public void put(T t) {
		lock.lock();
		try {
			while (list.size() == MAX) {
				System.out.println(Thread.currentThread().getName() + "等待中。。。");
				// 進入等待隊列,釋放鎖標記
				// 藉助條件,進入的等待隊列
				product.await();
			}
			System.out.println(Thread.currentThread().getName() + "put...");
			list.add(t);
			count++;
			// 藉助條件,喚醒全部的消費者
			consumer.signalAll();
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public T get() {
		T t = null;
		lock.lock();
		try {
			while (list.size() == 0) {
				System.out.println(Thread.currentThread().getName() + "等待...");
				consumer.await();
			}
			System.out.println(Thread.currentThread().getName() + "get...");
			t = list.removeFirst();
			count--;
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		} finally {
			lock.unlock();
		}
		return t;
	}

    public static void main(String[] args) {
		final TestContaniner<String> c=new TestContaniner<>();
		for(int i=0;i<10;i++){
			new Thread(new Runnable(){
				@Override
				public void run(){
					for(int j=0;j<5;j++){
						System.out.println(c.get());
					}
				}
			},"consumer"+i).start();
		}
		try{
			TimeUnit.SECONDS.sleep(2);
		}catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		for(int i=0;i<2;i++){
			new Thread(new Runnable(){
				@Override
				public void run(){
					for(int j=0;j<25;j++){
						c.put("container value"+j);
					}
				}
			},"producer"+i).start();
		}
	}
}

  Java 虛擬機中的同步(Synchronization)基於進入和退出管程(Monitor)對象實現。同步方 法 並非由 monitor enter 和 monitor exit 指令來實現同步的,而是由方法調用指令讀取運 行時常量池中方法的 ACC_SYNCHRONIZED 標誌來隱式實現的java

 

 對象頭:存儲對象的 hashCode、鎖信息或分代年齡或 GC 標誌,類型指針指向對象的類 元數據,JVM 經過這個指針肯定該對象是哪一個類的實例等信息。 實例變量:存放類的屬性數據信息,包括父類的屬性信息 填充數據:因爲虛擬機要求對象起始地址必須是 8 字節的整數倍。填充數據不是必須存 在的,僅僅是爲了字節對齊 當在對象上加鎖時,數據是記錄在對象頭中。當執行 synchronized 同步方法或同步代碼 塊時,會在對象頭中記錄鎖標記,鎖標記指向的是 monitor 對象(也稱爲管程或監視器鎖) 的起始地址。每一個對象都存在着一個 monitor 與之關聯,對象與其 monitor 之間的關係有 存在多種實現方式,如 monitor 能夠與對象一塊兒建立銷燬或當線程試圖獲取對象鎖時自動生 成,但當一個 monitor 被某個線程持有後,它便處於鎖定狀態。 在 Java 虛擬機(HotSpot)中,monitor 是由 ObjectMonitor 實現的。 ObjectMonitor 中有兩個隊列,_WaitSet 和 _EntryList,以及_Owner 標記。其中_WaitSet 是用於管理等待隊列(wait)線程的,_EntryList 是用於管理鎖池阻塞線程的,_Owner 標記用於 記錄當前執行線程。線程狀態圖以下: 多線程

 

 當多線程併發訪問 同一個同步代碼 時,首先會進入_EntryList,當線程獲取鎖標記後, monitor 中的_Owner 記錄此線程,並在 monitor 中的計數器執行遞增計算(+1),表明鎖定, 其餘線程在_EntryList 中繼續阻塞。若執行線程調用 wait 方法,則 monitor 中的計數器執行 賦值爲 0 計算,並將_Owner 標記賦值爲 null,表明放棄鎖,執行線程進如_WaitSet 中阻塞。 若執行線程調用 notify/notifyAll 方法,_WaitSet 中的線程被喚醒,進入_EntryList 中阻塞,等 待獲取鎖標記。若執行線程的同步代碼執行結束,一樣會釋放鎖標記,monitor 中的_Owner 標記賦值爲 null,且計數器賦值爲 0 計算併發

相關文章
相關標籤/搜索