JAVA多線程高併發之ReentrantLock講解lockInterruptibly方法

JAVA中多線程高併發場景下保證線程安全通常都會考慮加鎖。但是在特殊場景下我們也可以採用java.util.concurrent包提供的線程安全的對象,避免加鎖從而達到高效的目的。

但是,這些線程安全的對象僅僅指的是針對於原子性操作是線程安全的,如果多個方法同時調用無法保證線程安全,只能考慮加鎖。這裏我們舉個列子:假設我們在多線程高併發場景下使用java.util.concurrent.ConcurrentLinkedQueue這個對象來獲取隊列中的元素,可以直接調用poll()方法,不用加鎖也可以保證線程安全,假如我們在獲取的時候需要先判斷隊列是否爲空然後獲取,也就是先調用isEmpty()方法、接着調用poll()方法,這種情況就無法保證線程安全,因爲這裏是兩步操作,無法保證原子性。

ReentrantLock也是多線程併發時候加鎖一種方式,通常會用來和synchronized做比較。我簡單整理一下如下:

1、從使用方法角度對比

  1. ReentrantLock必須手動釋放鎖,synchronized不用考慮(發生異常自動釋放鎖)
  2. ReentrantLock可以嘗試鎖定 trylock
  3. ReentrantLock還可以調用lockInterruptibly方法,可以對線程interrupt方法做成響應
  4. ReentrantLock可以指定公平鎖Lock lock = new ReentrantLock(true)

2、從性能角度對比

  1. JDK1.5以前synchronized性能略低於ReentrantLock,包含JDK1.5版本
  2. JDK1.5以後Java虛擬機對synchronized做了很多優化,增加了偏向鎖、輕量級鎖(多數情況下是自旋鎖)、重量級鎖等細節。性能和ReentrantLock差不多。

我們來分析ReentrantLock 調用lockInterruptibly方法,可以對線程interrupt方法做成響應

package com.reentranlock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * ReentrantLock還可以調用lockInterruptibly方法,可以對線程interrupt方法做成響應
 *
 * @author 小輝哥/小輝GE
 * <p>
 * 2019年8月10日 下午15:30:00
 */
public class ReentrantLockInterrupt {

	public static void main(String[] args) {
		Lock lock = new ReentrantLock();
		Thread thread1 = new Thread(() -> {
			lock.lock();
			try {
				System.out.println("thread1 start......");
				TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
			} catch (InterruptedException e) {
				System.out.println("thread1" + "interrupt......");
			} finally {
				lock.unlock();
				System.out.println("thread1 end......");
			}
		});
		thread1.start();

		Thread thread2 = new Thread(() -> {
			boolean status = false;
			try {
				status = lock.tryLock();
				System.out.println("thread2 start......");
				// 可以對interrupt方法做出響應
				if (!status)
					lock.lockInterruptibly();
			} catch (InterruptedException e) {
				System.out.println("thread2" + "interrupt");
			} finally {
				if (status)
					lock.unlock();
				System.out.println("thread2 end");
			}
		});
		thread2.start();

		try {
			TimeUnit.SECONDS.sleep(5);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		thread2.interrupt();
	}

}

測試輸出結果如下:

結果分析:

thread1 和 thread2兩個線程啓動,thread1 sleep很久,thread2調用lockInterruptibly方法,可以對線程interrupt方法做成響應,直接結束。這就是ReentrantLock可以對等待的線程進行打斷,很強悍吧。

以上代碼僅供參考,如有不當之處,歡迎指出!!!

更多幹貨,歡迎大家關注和聯繫我。期待和大家一起更好的交流、探討技術!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章