Lock 實現提供了比使用 synchronized 方法和語句可得到的更普遍的鎖定操做。此實現容許更靈活的結構,能夠具備差異很大的屬性,能夠支持多個相關的 Condition 對象。 鎖是控制多個線程對共享資源進行訪問的工具。一般,鎖提供了對共享資源的獨佔訪問。一次只能有一個線程得到鎖,對共享資源的全部訪問都須要首先得到鎖。不過,某些鎖可能容許對共享資源併發訪問,如 ReadWriteLock 的讀取鎖。 synchronized 方法或語句的使用提供了對與每一個對象相關的隱式監視器鎖的訪問,但卻強制全部鎖獲取和釋放均要出如今一個塊結構中:當獲取了多個鎖時,它們必須以相反的順序釋放,且必須在與全部鎖被獲取時相同的詞法範圍內釋放全部鎖。 雖然 synchronized 方法和語句的範圍機制使得使用監視器鎖編程方便了不少,並且還幫助避免了不少涉及到鎖的常見編程錯誤,但有時也須要以更爲靈活的方式使用鎖。例如,某些遍歷併發訪問的數據結果的算法要求使用 "hand-over-hand" 或 "chain locking":獲取節點 A 的鎖,而後再獲取節點 B 的鎖,而後釋放 A 並獲取 C,而後釋放 B 並獲取 D,依此類推。Lock 接口的實現容許鎖在不一樣的做用範圍內獲取和釋放,並容許以任何順序獲取和釋放多個鎖,從而支持使用這種技術。 Condition 將 Object 監視器方法(wait、notify 和 notifyAll)分解成大相徑庭的對象,以便經過將這些對象與任意 Lock 實現組合使用,爲每一個對象提供多個等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和語句的使用,Condition 替代了 Object 監視器方法的使用。 條件(也稱爲條件隊列 或條件變量)爲線程提供了一個含義,以便在某個狀態條件如今可能爲 true 的另外一個線程通知它以前,一直掛起該線程(即讓其「等待」)。由於訪問此共享狀態信息發生在不一樣的線程中,因此它必須受保護,所以要將某種形式的鎖與該條件相關聯。等待提供一個條件的主要屬性是:以原子方式 釋放相關的鎖,並掛起當前線程,就像 Object.wait 作的那樣。 Condition 實例實質上被綁定到一個鎖上。要爲特定 Lock 實例得到 Condition 實例,請使用其 newCondition() 方法。 主要相同點:Lock能完成Synchronized所實現的全部功能。 主要不一樣點:Lock有比Synchronized更精確的縣城予以和更好的性能。Synchronized會自動釋放鎖,可是Lock必定要求程序員手工釋放,而且必須在finally從句中釋放。 synchronized 修飾方法時 表示同一個對象在不一樣的線程中 表現爲同步隊列 若是實例化不一樣的對象 那麼synchronized就不會出現同步效果了。 1.對象的鎖 全部對象都自動含有單一的鎖。 JVM負責跟蹤對象被加鎖的次數。若是一個對象被解鎖,其計數變爲0。在任務(線程)第一次給對象加鎖的時候,計數變爲1。每當這個相同的任務(線程)在此對象上得到鎖時,計數會遞增。 只有首先得到鎖的任務(線程)才能繼續獲取該對象上的多個鎖。 每當任務離開一個synchronized方法,計數遞減,當計數爲0的時候,鎖被徹底釋放,此時別的任務就可使用此資源。 2.synchronized同步塊 2.1同步到單一對象鎖 當使用同步塊時,若是方法下的同步塊都同步到一個對象上的鎖,則全部的任務(線程)只能互斥的進入這些同步塊。 Resource1.java演示了三個線程(包括main線程)試圖進入某個類的三個不一樣的方法的同步塊中,雖然這些同步塊處在不一樣的方法中,但因爲是同步到同一個對象(當前對象 synchronized (this)),因此對它們的方法依然是互斥的。 package com.org.thread; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** *@DEMO:JavaSE *@Author:jilongliang *@Date:2013-3-21 */ public class Locker { public static void main(String[] args) { Resources1 res = new Resources1(); Pro p = new Pro(res); Customer1 c = new Customer1(res); new Thread(p).start(); new Thread(c).start(); } } class Pro implements Runnable { Resources1 resource; Pro(Resources1 res) { this.resource = res; } @Override public void run() { while (true) { try { resource.set("商品"); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Customer1 implements Runnable { Resources1 res; Customer1(Resources1 res) { this.res = res; } @Override public void run() { while (true) { synchronized (res) { try { res.out(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } /** * wait notify notifyAll 都在使用在同步中,由於要對持有監視器(鎖)的線程 操做 因此要使用在同步中,由於只有同步才具備鎖 * 爲何這些操做線程的方法要定義Object類中? * 由於這些方法在操做同步中線程時,都必需要標識他們所操做線程只有的鎖 * 只有同一個鎖上的被等待線程,能夠被同一個鎖上的notify喚醒 不能夠對不一樣鎖中的線程進行喚醒 * 也就是說,等待和喚醒必須是同一個鎖 而鎖能夠是任意對象,因此能夠被任意對象調用的方法定義了 * Object類中 */ class Resources1 { private String name; private int count = 1; private boolean flag = false; private Lock lock = new ReentrantLock(); private Condition condition_pro = lock.newCondition(); private Condition condition_con = lock.newCondition(); public void set(String name) throws InterruptedException { lock.lock(); try { while (flag) // this.wait(); condition_pro.await();// 等待 this.name = name + "=生產數:" + count++; System.out.println(Thread.currentThread().getName() + "生產者:" + this.name); flag = true; condition_con.signalAll(); // this.notifyAll(); } finally { lock.unlock(); } } public void out() throws InterruptedException { lock.lock(); try { while (!flag) // this.wait(); condition_con.await(); System.out.println(Thread.currentThread().getName() + "消費者===========" + this.name); flag = false; condition_pro.signalAll(); // this.notifyAll(); } finally { lock.unlock(); } } }