欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java多線程之顯示鎖和內(nèi)置鎖總結(jié)詳解

 更新時間:2017年11月17日 15:59:25   作者:huangshulang1234  
這篇文章主要介紹了Java多線程之顯示鎖和內(nèi)置鎖總結(jié)詳解,具有一定參考價值,需要的朋友可以了解下。

總結(jié)多線程之顯示鎖和內(nèi)置鎖

Java中具有通過Synchronized實現(xiàn)的內(nèi)置鎖,和ReentrantLock實現(xiàn)的顯示鎖,這兩種鎖各有各的好處,算是互有補充,這篇文章就是做一個總結(jié)。

*Synchronized*

內(nèi)置鎖獲得鎖和釋放鎖是隱式的,進入synchronized修飾的代碼就獲得鎖,走出相應(yīng)的代碼就釋放鎖。

synchronized(list){ //獲得鎖
  list.append();
  list.count();
}//釋放鎖

通信

與Synchronized配套使用的通信方法通常有wait(),notify()。

wait()方法會立即釋放當(dāng)前鎖,并進入等待狀態(tài),等待到相應(yīng)的notify并重新獲得鎖過后才能繼續(xù)執(zhí)行;notify()不會立刻立刻釋放鎖,必須要等notify()所在線程執(zhí)行完synchronized塊中的所有代碼才會釋放。用如下代碼來進行驗證:

public static void main(String[] args){
	List list = new LinkedList();
	Thread r = new Thread(new ReadList(list));
	Thread w = new Thread(new WriteList(list));
	r.start();
	w.start();
}
class ReadList implements Runnable{
	private List list;
	public ReadList(List list){
		this.list = list;
	}
	@Override
	  public void run(){
		System.out.println("ReadList begin at "+System.currentTimeMillis());
		synchronized (list){
			try {
				Thread.sleep(1000);
				System.out.println("list.wait() begin at "+System.currentTimeMillis());
				list.wait();
				System.out.println("list.wait() end at "+System.currentTimeMillis());
			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("ReadList end at "+System.currentTimeMillis());
	}
}
class WriteList implements Runnable{
	private List list;
	public WriteList(List list){
		this.list = list;
	}
	@Override
	  public void run(){
		System.out.println("WriteList begin at "+System.currentTimeMillis());
		synchronized (list){
			System.out.println("get lock at "+System.currentTimeMillis());
			list.notify();
			System.out.println("list.notify() at "+System.currentTimeMillis());
			try {
				Thread.sleep(2000);
			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("get out of block at "+System.currentTimeMillis());
		}
		System.out.println("WriteList end at "+System.currentTimeMillis());
	}
}

運行結(jié)果:

ReadList begin at 1493650526582
WriteList begin at 1493650526582
list.wait() begin at 1493650527584
get lock at 1493650527584
list.notify() at 1493650527584
get out of block at 1493650529584
WriteList end at 1493650529584
list.wait() end at 1493650529584
ReadList end at 1493650529584

可見讀線程開始運行,開始wait過后,寫線程才獲得鎖;寫線程走出同步塊而不是notify過后,讀線程才wait結(jié)束,亦即獲得鎖。所以notify不會釋放鎖,wait會釋放鎖。值得一提的是,notifyall()會通知等待隊列中的所有線程。

編碼

編碼模式比較簡單,單一,不必顯示的獲得鎖,釋放鎖,能降低因粗心忘記釋放鎖的錯誤。使用模式如下:

synchronized(object){ 
 
}

靈活性

1.內(nèi)置鎖在進入同步塊時,采取的是無限等待的策略,一旦開始等待,就既不能中斷也不能取消,容易產(chǎn)生饑餓與死鎖的問題
2.在線程調(diào)用notify方法時,會隨機選擇相應(yīng)對象的等待隊列的一個線程將其喚醒,而不是按照FIFO的方式,如果有強烈的公平性要求,比如FIFO就無法滿足

性能

Synchronized在JDK1.5及之前性能(主要指吞吐率)比較差,擴展性也不如ReentrantLock。但是JDK1.6以后,修改了管理內(nèi)置鎖的算法,使得Synchronized和標(biāo)準的ReentrantLock性能差別不大。

*ReentrantLock*

ReentrantLock是顯示鎖,需要顯示進行 lock 以及 unlock 操作。

通信

與ReentrantLock搭配的通行方式是Condition,如下:

private Lock lock = new ReentrantLock(); 
private Condition condition = lock.newCondition(); 
condition.await();//this.wait(); 
condition.signal();//this.notify(); 
condition.signalAll();//this.notifyAll();

Condition是被綁定到Lock上的,必須使用lock.newCondition()才能創(chuàng)建一個Condition。從上面的代碼可以看出,Synchronized能實現(xiàn)的通信方式,Condition都可以實現(xiàn),功能類似的代碼寫在同一行中。而Condition的優(yōu)秀之處在于它可以為多個線程間建立不同的Condition,比如對象的讀/寫Condition,隊列的空/滿Condition,在JDK源碼中的ArrayBlockingQueue中就使用了這個特性:

public ArrayBlockingQueue(int capacity, boolean fair) {
  if (capacity <= 0)
    throw new IllegalArgumentException();
  this.items = new Object[capacity];
  lock = new ReentrantLock(fair);
  notEmpty = lock.newCondition();
  notFull = lock.newCondition();
}
public void put(E e) throws InterruptedException {
  checkNotNull(e);
  final ReentrantLock lock = this.lock;
  lock.lockInterruptibly();
  try {
    while (count == items.length)
      notFull.await();
    enqueue(e);
  } finally {
    lock.unlock();
  }
}
public E take() throws InterruptedException {
  final ReentrantLock lock = this.lock;
  lock.lockInterruptibly();
  try {
    while (count == 0)
      notEmpty.await();
    return dequeue();
  } finally {
    lock.unlock();
  }
}
private void enqueue(E x) {
  // assert lock.getHoldCount() == 1;
  // assert items[putIndex] == null;
  final Object[] items = this.items;
  items[putIndex] = x;
  if (++putIndex == items.length)
    putIndex = 0;
  count++;
  notEmpty.signal();
}
private E dequeue() {
  // assert lock.getHoldCount() == 1;
  // assert items[takeIndex] != null;
  final Object[] items = this.items;
  @SuppressWarnings("unchecked")
  E x = (E) items[takeIndex];
  items[takeIndex] = null;
  if (++takeIndex == items.length)
    takeIndex = 0;
  count--;
  if (itrs != null)
    itrs.elementDequeued();
  notFull.signal();
  return x;
}

編碼

Lock lock = new ReentrantLock();
lock.lock();
try{
 
}finally{
  lock.unlock();
}

相比于Synchronized要復(fù)雜一些,而且一定要記得在finally中釋放鎖而不是其他地方,這樣才能保證即使出了異常也能釋放鎖。

靈活性

1.lock.lockInterruptibly()可以使得線程在等待鎖是支持響應(yīng)中斷;lock.tryLock()可以使得線程在等待一段時間過后如果還未獲得鎖就停止等待而非一直等待。有了這兩種機制就可以更好的制定獲得鎖的重試機制,而非盲目一直等待,可以更好的避免饑餓和死鎖問題

2.ReentrantLock可以成為公平鎖(非默認的),所謂公平鎖就是鎖的等待隊列的FIFO,不過公平鎖會帶來性能消耗,如果不是必須的不建議使用。這和CPU對指令進行重排序的理由是相似的,如果強行的按照代碼的書寫順序來執(zhí)行指令,就會浪費許多時鐘周期,達不到最大利用率

性能

雖然Synchronized和標(biāo)準的ReentrantLock性能差別不大,但是ReentrantLock還提供了一種非互斥的讀寫鎖,

也就是不強制每次最多只有一個線程能持有鎖,它會避免“讀/寫”沖突,“寫/寫”沖突,但是不會排除“讀/讀”沖突,

因為“讀/讀”并不影響數(shù)據(jù)的完整性,所以可以多個讀線程同時持有鎖,這樣在讀寫比較高的情況下,性能會有很大的提升。

下面用兩種鎖分別實現(xiàn)的線程安全的linkedlist:

class RWLockList {
	//讀寫鎖
	private List list;
	private final ReadWriteLock lock = new ReentrantReadWriteLock();
	private final Lock readLock = lock.readLock();
	private final Lock writeLock = lock.writeLock();
	public RWLockList(List list){
		this.list = list;
	}
	public int get(int k) {
		readLock.lock();
		try {
			return (int)list.get(k);
		}
		finally {
			readLock.unlock();
		}
	}
	public void put(int value) {
		writeLock.lock();
		try {
			list.add(value);
		}
		finally {
			writeLock.unlock();
		}
	}
}
class SyncList {
	private List list;
	public SyncList(List list){
		this.list = list;
	}
	public synchronized int get(int k){
		return (int)list.get(k);
	}
	public synchronized void put(int value){
		list.add(value);
	}
}

讀寫鎖測試代碼:

List list = new LinkedList();
for (int i=0;i<10000;i++){
	list.add(i);
}
RWLockList rwLockList = new RWLockList(list);
//初始化數(shù)據(jù)
Thread writer = new Thread(new Runnable() {
	@Override
	  public void run() {
		for (int i=0;i<10000;i++){
			rwLockList.put(i);
		}
	}
}
);
Thread reader1 = new Thread(new Runnable() {
	@Override
	  public void run() {
		for (int i=0;i<10000;i++){
			rwLockList.get(i);
		}
	}
}
);
Thread reader2 = new Thread(new Runnable() {
	@Override
	  public void run() {
		for (int i=0;i<10000;i++){
			rwLockList.get(i);
		}
	}
}
);
long begin = System.currentTimeMillis();
writer.start();
reader1.start();
reader2.start();
try {
	writer.join();
	reader1.join();
	reader2.join();
}
catch (InterruptedException e) {
	e.printStackTrace();
}
System.out.println("RWLockList take "+(System.currentTimeMillis()-begin) + "ms");

同步鎖測試代碼:

List list = new LinkedList();
for (int i=0;i<10000;i++){
  list.add(i);
}
SyncList syncList = new SyncList(list);//初始化數(shù)據(jù)
Thread writerS = new Thread(new Runnable() {
  @Override
  public void run() {
    for (int i=0;i<10000;i++){
      syncList.put(i);
    }
  }
});
Thread reader1S = new Thread(new Runnable() {
  @Override
  public void run() {
    for (int i=0;i<10000;i++){
      syncList.get(i);
    }
  }
});
Thread reader2S = new Thread(new Runnable() {
  @Override
  public void run() {
    for (int i=0;i<10000;i++){
      syncList.get(i);
    }
  }
});
long begin1 = System.currentTimeMillis();
writerS.start();reader1S.start();reader2S.start();
try {
  writerS.join();
  reader1S.join();
  reader2S.join();
} catch (InterruptedException e) {
  e.printStackTrace();
}
System.out.println("SyncList take "+(System.currentTimeMillis()-begin1) + "ms");

結(jié)果:

RWLockList take 248ms
RWLockList take 255ms
RWLockList take 249ms
RWLockList take 224ms
 
SyncList take 351ms
SyncList take 367ms
SyncList take 315ms
SyncList take 323ms

可見讀寫鎖的確是優(yōu)于純碎的互斥鎖

總結(jié)

內(nèi)置鎖最大優(yōu)點是簡潔易用,顯示鎖最大優(yōu)點是功能豐富,所以能用內(nèi)置鎖就用內(nèi)置鎖,在內(nèi)置鎖功能不能滿足之時在考慮顯示鎖。

以上就是本文關(guān)于Java多線程之顯示鎖和內(nèi)置鎖總結(jié)詳解的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:

Java多線程中斷機制三種方法及示例

淺談Java多線程的優(yōu)點及代碼示例

Java利用future及時獲取多線程運行結(jié)果

如有不足之處,歡迎留言指出。

相關(guān)文章

  • 淺談java監(jiān)聽器的作用

    淺談java監(jiān)聽器的作用

    這篇文章主要介紹了淺談java監(jiān)聽器的作用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 淺析Spring的事務(wù)實現(xiàn)原理

    淺析Spring的事務(wù)實現(xiàn)原理

    這篇文章主要為大家詳細介紹了Spring中事務(wù)實現(xiàn)的原理,文中的示例代碼講解詳細,對我們學(xué)習(xí)Spring有一定的幫助,需要的可以參考一下
    2022-11-11
  • SpringBoot實現(xiàn)過濾器和攔截器的方法

    SpringBoot實現(xiàn)過濾器和攔截器的方法

    大家應(yīng)該都曉得實現(xiàn)過濾器需要實現(xiàn)?javax.servlet.Filter?接口,而攔截器會在處理指定請求之前和之后進行相關(guān)操作,配置攔截器需要兩步,本文通過實例代碼給大家介紹SpringBoot?過濾器和攔截器的相關(guān)知識,感興趣的朋友一起看看吧
    2022-11-11
  • Java獲取客戶端真實IP地址過程解析

    Java獲取客戶端真實IP地址過程解析

    這篇文章主要介紹了Java獲取客戶端真實IP地址過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01
  • Spring超詳細講解IOC與解耦合

    Spring超詳細講解IOC與解耦合

    IoC就是比方說有一個類,我們想要調(diào)用類里面的方法(不是靜態(tài)方法),就要創(chuàng)建該類的對象,使用對象調(diào)用方法來實現(xiàn)。但對于Spring來說,Spring創(chuàng)建對象的過程,不是在代碼里面實現(xiàn)的,而是交給Spring來進行配置實現(xiàn)的
    2022-08-08
  • 布隆過濾器(Bloom Filter)的Java實現(xiàn)方法

    布隆過濾器(Bloom Filter)的Java實現(xiàn)方法

    下面小編就為大家?guī)硪黄悸∵^濾器(Bloom Filter)的Java實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • Java String中移除空白字符的多種方式匯總

    Java String中移除空白字符的多種方式匯總

    這篇文章主要給大家介紹了關(guān)于Java String中移除空白字符的多種方式,文中通過圖文介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java編程幾個循環(huán)實例代碼分享

    Java編程幾個循環(huán)實例代碼分享

    這篇文章主要介紹了Java編程幾個循環(huán)實例代碼分享,多看多練,小編覺得還是挺不錯的,這里分享給大家,供需要的朋友參考。
    2017-10-10
  • 詳解Springboot應(yīng)用中設(shè)置Cookie的SameSite屬性

    詳解Springboot應(yīng)用中設(shè)置Cookie的SameSite屬性

    Chrome 51 開始,瀏覽器的 Cookie 新增加了一個SameSite屬性,用來防止 CSRF 攻擊和用戶追蹤。今天通過本文給大家介紹Springboot應(yīng)用中設(shè)置Cookie的SameSite屬性,感興趣的朋友一起看看吧
    2022-01-01
  • spring boot 結(jié)合jsp案例詳解

    spring boot 結(jié)合jsp案例詳解

    這篇文章主要介紹了spring boot 結(jié)合jsp案例詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10

最新評論