Synchronized是併發中使用最頻繁的關鍵字了,它可使用在方法、代碼塊上,表示對該段代碼加鎖,而必需要持有鎖才能執行這段代碼。Synchronized具備互斥性。java
提及來蠻簡單,而實際中編程 ,最可貴地方有兩點編程
一、肯定併發間隙多線程
二、肯定鎖的對象併發
作好這兩點才能處理好鎖的粒度,是併發的性能更好。ide
eg一、Synchronized加在靜態方法上,不一樣的線程調用這兩個方法互斥。此時synchronize鎖的是該類性能
public class SynchronizeDemo1 { public synchronized static void fool1() throws Exception{ System.out.println("fool1...開始"); Thread.sleep(10000L); System.out.println("fool1...結束"); } public synchronized static void fool2() throws Exception{ System.out.println("fool2...開始"); Thread.sleep(5000L); System.out.println("fool2...結束"); } public static void main(String args[]){ new Thread(new Runnable() { @Override public void run() { try { SynchronizeDemo1.fool1(); } catch (Exception e) { e.printStackTrace(); } } }).start(); new Thread(new Runnable() { @Override public void run() { try { SynchronizeDemo1.fool2(); } catch (Exception e) { e.printStackTrace(); } } }).start();; } }
eg二、Synchronized加在成員方法上,不一樣的線程調用同一對象的成員方法互斥this
package com.base.thread.synchronize; public class SynchronizeDemo2 { public synchronized void fool1() throws Exception{ System.out.println("fool1...開始"); Thread.sleep(10000L); System.out.println("fool1...結束"); } public synchronized void fool2() throws Exception{ System.out.println("fool2...開始"); Thread.sleep(5000L); System.out.println("fool2...結束"); } public static void main(String args[]){ final SynchronizeDemo2 synchronizeDemo2 = new SynchronizeDemo2(); new Thread(new Runnable() { @Override public void run() { try { // new SynchronizeDemo2().fool1(); synchronizeDemo2.fool1(); } catch (Exception e) { e.printStackTrace(); } } }).start(); new Thread(new Runnable() { @Override public void run() { try { // new SynchronizeDemo2().fool2(); synchronizeDemo2.fool1(); } catch (Exception e) { e.printStackTrace(); } } }).start();; } }
eg三、foo3和foo4不互斥,foo1和foo4互斥,foo2和foo3互斥線程
public class SynchronizeDemo3 { public static synchronized void fool1() throws Exception{ System.out.println("fool1...開始"); Thread.sleep(10000L); System.out.println("fool1...結束"); } public synchronized void fool2() throws Exception{ System.out.println("fool2...開始"); Thread.sleep(5000L); System.out.println("fool2...結束"); } public void fool3() throws Exception{ synchronized(this){ System.out.println("fool3...開始"); Thread.sleep(5000L); System.out.println("fool3...結束"); } } public void fool4() throws Exception{ synchronized(SynchronizeDemo3.class){ System.out.println("fool4...開始"); Thread.sleep(5000L); System.out.println("fool4...結束"); } } public static void main(String args[]){ new Thread(new Runnable() { @Override public void run() { try { new SynchronizeDemo3().fool3(); } catch (Exception e) { e.printStackTrace(); } } }).start(); new Thread(new Runnable() { @Override public void run() { try { new SynchronizeDemo3().fool4(); } catch (Exception e) { e.printStackTrace(); } } }).start();; } }
LOCKcode
Lock比synchronized更加面向對象,鎖自己就是一個對象。兩個線程執行的代碼片斷要實現同步互斥的效果,它們必須用同一個Lock對象。對象
ReentrantLock
ReentrantLock是Lock的實現,被稱做重入鎖,它的功能比Synchronized強大,可是jdk1.6以後二者性能差異不大,Synchronized使用更簡單清晰,因此多線程加鎖仍是首選Synchronized。
ReentrantLock提供了公平和非公平兩種鎖。經過構造方法能夠實現,可是公平鎖的性能遠遠低於非公平鎖,所以非特殊狀況優先非公平鎖。
注意:ReenTrantLock使用以後,必須釋放鎖。
ReentrantLock 鎖提供了以下重要的方法:
lock():得到鎖,若是鎖已經被佔用,則等待
lockInterruptibly():得到鎖,但優先響應中斷
tryLock():嘗試得到鎖,若是成功,返回true,失敗返回false。該方法不等待,當即返回
unlock():釋放鎖
ReentrantReadWriteLock 讀寫鎖
分爲讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥。若是代碼是隻讀數據,能夠不少人同時讀,但不能同時寫,那就上讀鎖;若是你的代碼修改數據,只能有一我的在寫,且不能同時讀取,那就上寫鎖。總之,讀的時候上讀鎖,寫的時候上寫鎖!
public class ReadWriteLockTest{ private Integer num = 0; private Lock lock = new ReentrantLock(); private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); private ReadLock readLock = reentrantReadWriteLock.readLock(); private WriteLock writeLock = reentrantReadWriteLock.writeLock(); public int read1(){ try{ lock.lock(); Thread.sleep(10L); }catch(Exception e){ e.printStackTrace(); }finally{ lock.unlock(); } return num; } public void write1(){ try{ lock.lock(); num++; }finally{ lock.unlock(); } } public int read2(){ try{ readLock.lock(); Thread.sleep(10L); }catch(Exception e){ e.printStackTrace(); }finally{ readLock.unlock(); } return num; } public void write2(){ try{ writeLock.lock(); num++; }finally{ writeLock.unlock(); } } public Integer getNum() { return num; } public static void main(String args[]) throws Exception{ long time1 = System.currentTimeMillis(); final ReadWriteLockTest rwt = new ReadWriteLockTest(); List<Thread> threadList = new ArrayList<>(); for(int i = 0; i < 3000; i++){ Thread t1 = new Thread(new Runnable() { @Override public void run() { rwt.write1(); // rwt.write2(); } }); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { rwt.read1(); // rwt.read2(); } }); t2.start(); threadList.add(t1); threadList.add(t2); } for(Thread thread : threadList){ thread.join(); } System.out.println("num: " + rwt.getNum()); System.out.println("耗時:" + (System.currentTimeMillis() - time1)); } }
Condition
Condition能夠替代傳統的線程間通訊,用await()替換wait(),用signal()替換notify(),用signalAll()替換notifyAll()。
——爲何方法名不直接叫wait()/notify()/nofityAll()?由於Object的這幾個方法是final的,不可重寫!
傳統線程的通訊方式,Condition均可以實現。
注意,Condition是被綁定到Lock上的,要建立一個Lock的Condition必須用newCondition()方法。
Condition的強大之處在於它能夠爲多個線程間創建不一樣的Condition