package thread; /** * synchronized修飾實例方法、靜態方法、代碼塊,修飾實例方法和代碼塊時候用this對象當鎖,修改靜態方法時用類的class對象當鎖 * synchronized是悲觀鎖,synchronized和ReentrantLock等獨佔鎖就是悲觀鎖思想的實現 * synchronized是可重入鎖 * synchronized是非公平鎖 * 做爲鎖的條件:必須是對象且被多個線程共享才能做爲鎖 * */ public class SynchronizedDemo { private int a; public int getA() { return a; } public void setA(int a) { this.a = a; } public void add(){ synchronized(this){ int x = getA(); setA(x+1); } } public static void main(String[] args) throws InterruptedException { final SynchronizedDemo synchronizedDemo = new SynchronizedDemo(); for (int i = 0; i < 100000; i++) { new Thread(new Runnable() { @Override public void run() { synchronizedDemo.add(); } }).start(); } Thread.sleep(10000); System.err.println(synchronizedDemo.getA()); } }
lock
package thread; import java.util.concurrent.locks.ReentrantLock; /** * 一、鎖像synchronized同步塊同樣,是一種線程同步機制,但比Java中的synchronized同步塊更復雜,由於鎖(以及其它更高級的線程同步機制) * 是由synchronized同步塊的方式實現的 * * 二、樂觀鎖與悲觀鎖 * 樂觀鎖適用於讀比較多的場景,悲觀鎖適用於寫比較多的場景,不加鎖會帶來大量的性能提高 * 樂觀鎖常見的兩種實現方式:版本號機制或CAS算法實現 * 版本號機制:通常是在數據表中加上一個數據版本號version字段,當數據被修改時,version值會加一。當線程A要更新數據值時,在讀取數據的同時也會讀取version值, * 在提交更新時,若剛纔讀取到的version值爲當前數據庫中的version值相等時才更新,不然重試更新操做,直到更新成功 * * 三、CAS算法 * 即 compare and swap(比較與交換),是一種有名的無鎖算法,即不使用鎖的狀況下實現多線程之間的變量同步,也就是在沒有線程被阻塞的狀況下實現變量的同步, * 因此也叫非阻塞同步 * check and act模式,先檢查後操做模式 首先檢查一個變量的值,而後再基於這個值作一些操做,check then act操做必須是原子的。 * 原子就是說」check「操做和」act「被當作一個原子代碼塊執行。不存在多個線程同時執行原子塊 * CAS有3個操做數,內存值V,預期值A,要修改的新值B。當且僅當預期值A和內存值V相同時,將內存值V修改成B,不然什麼都不作 * * 四、可重入鎖:假如一把鎖鎖了n個地方,那麼只要獲得這把鎖,那n個地方均可以訪問 * * 五、獨享鎖和共享鎖 * 獨享鎖:是指該鎖一次只能被一個線程所持有。實現:ReentrantLock * 共享鎖:是指該鎖可被多個線程所持有。實現:ReadWriteLock,讀鎖是共享鎖,寫鎖是獨享鎖。由於讀讀能夠同時進行,而讀寫、寫寫不能同時進行 * * 六、公平鎖、非公平鎖:公平鎖是指多個線程按照申請鎖的順序來獲取鎖。 * * 七、分段鎖 * 分段鎖實際上是一種鎖的設計,並非具體的一種鎖,對於ConcurrentHashMap而言,其併發的實現就是經過分段鎖的形式來實現高效的併發操做 * 當須要put元素的時候,並非對整個hashmap進行加鎖,而是先經過hashcode來知道他要放在哪個分段中,而後對這個分段進行加鎖,因此當多線程put的時候, * 只要不是放在一個分段中,就實現了真正的並行的插入 * * 八、偏向鎖/輕量級鎖/重量級鎖,這三種鎖是指鎖的狀態,而且是針對Synchronized * * 九、AQS是抽象隊列同步器,維護了一個volatile int state(表明共享資源)和一個FIFO線程等待隊列(多線程爭用資源被阻塞時會進入此隊列) * * 十、自旋鎖:在Java中,自旋鎖是指嘗試獲取鎖的線程不會當即阻塞,而是採用循環的方式去嘗試獲取鎖,這樣的好處是減小線程上下文切換的消耗,缺點是循環會消耗CPU * 獲取不到鎖的線程要麼阻塞,要麼自旋 */ public class LockDemo { private int a; //經過構造函數指定是否爲公平鎖 private ReentrantLock reentrantLock=new ReentrantLock(true); //private ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock(); public int getA() { return a; } public void setA(int a) { this.a = a; } public void add(){ reentrantLock.lock(); //reentrantReadWriteLock.readLock().lock(); try { int x = getA(); setA(x+1); } finally { reentrantLock.unlock(); //reentrantReadWriteLock.readLock().unlock(); } } public static void main(String[] args) throws InterruptedException { final LockDemo lockDemo = new LockDemo(); for (int i = 0; i < 100000; i++) { new Thread(new Runnable() { @Override public void run() { lockDemo.add(); } }).start(); } Thread.sleep(10000); System.err.println(lockDemo.getA()); } }
二者區別
1.首先synchronized是java內置關鍵字,在jvm層面,Lock是個java類; 2.synchronized沒法判斷是否獲取到鎖,Lock能夠判斷是否獲取到鎖; 3.synchronized會自動釋放鎖(執行完代碼或發生異常會釋放鎖),Lock需在finally中手工釋放鎖,不然容易形成線程死鎖; 4.用synchronized關鍵字的兩個線程1和線程2,若是當前線程1得到鎖,線程2線程等待。若是線程1阻塞,線程2則會一直等待下去,而Lock鎖就不必定會等待下去,若是嘗試獲取不到鎖,線程能夠不用一直等待就結束了; 5.synchronized的鎖可重入、不可中斷、非公平,而Lock鎖可重入、可中斷、能夠設置是否公平 6.Lock鎖適合大量同步的代碼的同步問題,synchronized鎖適合代碼少許的同步問題