Synchronized與Lock

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

相關文章
相關標籤/搜索