synchronized和ReentrantLock區別淺析
一、什麼是sychronized
sychronized是java中最基本同步互斥的手段,可以修飾程式碼塊,方法,類.
在修飾程式碼塊的時候需要一個reference物件作為鎖的物件.
在修飾方法的時候預設是當前物件作為鎖的物件.
在修飾類時候預設是當前類的Class物件作為鎖的物件.
synchronized會在進入同步塊的前後分別形成monitorenter和monitorexit位元組碼指令.在執行monitorenter指令時會嘗試獲取物件的鎖,如果此沒物件沒有被鎖,或者此物件已經被當前執行緒鎖住,那麼鎖的計數器加一,每當monitorexit被鎖的物件的計數器減一.直到為0就釋放該物件的鎖.由此synchronized是可重入的,不會出現自己把自己鎖死.
二、什麼ReentrantLock
以物件的方式來操作物件鎖.相對於sychronized需要在finally中去釋放鎖。
三、synchronized和ReentrantLock的區別
1. 等待可中斷
在持有鎖的執行緒長時間不釋放鎖的時候,等待的執行緒可以選擇放棄等待. tryLock(long timeout, TimeUnit unit)。
ReentrantLock 擁有Synchronized相同的併發性和記憶體語義,此外還多了 鎖投票,定時鎖等候和中斷鎖等候。
執行緒A和B都要獲取物件O的鎖定,假設A獲取了物件O鎖,B將等待A釋放對O的鎖定。
如果使用 synchronized ,如果A不釋放,B將一直等下去,不能被中斷。
如果使用ReentrantLock,如果A不釋放,可以使B在等待了足夠長的時間以後,中斷等待,而幹別的事情。
ReentrantLock獲取鎖定與三種方式:
a) lock(), 如果獲取了鎖立即返回,如果別的執行緒持有鎖,當前執行緒則一直處於休眠狀態,直到獲取鎖
b) tryLock(), 如果獲取了鎖立即返回true,如果別的執行緒正持有鎖,立即返回false;
c) tryLock (long timeout, TimeUnit unit), 如果獲取了鎖定立即返回true,如果別的執行緒正持有鎖,會等待引數給定的時間,在等待的過程中,如果獲取了鎖定,就返回true,如果等待超時,返回false;
d) lockInterruptibly: 如果獲取了鎖定立即返回,如果沒有獲取鎖定,當前執行緒處於休眠狀態,直到或者鎖定,或者當前執行緒被別的執行緒中斷
2.公平鎖與非公平鎖
按照申請鎖的順序來一次獲得鎖稱為公平鎖.synchronized的是非公平鎖,ReentrantLock可以通過建構函式實現公平鎖. new RenentrantLock(boolean fair)
3.繫結多個Condition
通過多次newCondition可以獲得多個Condition物件,可以簡單的實現比較複雜的執行緒同步的功能.通過await(),signal()
此外,synchronized是在JVM層面上實現的,不但可以通過一些監控工具監控synchronized的鎖定,而且在程式碼執行時出現異常,JVM會自動釋放鎖定,但是使用Lock則不行,lock是通過程式碼實現的,要保證鎖定一定會被釋放,就必須將 unLock()放到finally{} 中。在資源競爭不是很激烈的情況下,Synchronized的效能要優於ReetrantLock,但是在資源競爭很激烈的情況下,Synchronized的效能會下降幾十倍,但是ReetrantLock的效能能維持常態。
四、例項演示
ReentrantLock 的lock機制有2種,忽略中斷鎖和響應中斷鎖,這給我們帶來了很大的靈活性。比如:如果A、B兩個執行緒去競爭鎖,A執行緒得到了鎖,B執行緒等待,但是A執行緒這個時候實在有太多事情要處理,就是一直不返回,B執行緒可能就會等不及了,想中斷自己,不再等待這個鎖了,轉而處理其他事情。這個時候ReentrantLock就提供了兩種機制:
一、B執行緒中斷自己(或者別的執行緒中斷它),但ReentrantLock 不去響應,讓B執行緒繼續等待,你再怎麼中斷,我全當耳邊風(synchronized原語就是如此);
二、B執行緒中斷自己(或者別的執行緒中斷它),ReentrantLock 處理了這個中斷,並且不再等待這個鎖的到來,完全放棄。
請看例子:
package zmx.multithread.test.reentrantlock;
import java.util.concurrent.locks.ReentrantLock;
/**
*
* @author zhangwenchao
*
*/
public class ReentrantLockTest {
//是用ReentrantLock,還是用synchronized
public static boolean useSynchronized = false;
public static void main(String[] args) {
IBuffer buff = null;
if(useSynchronized){
buff = new Buffer();
}else{
buff = new BufferInterruptibly();
}
final Writer writer = new Writer(buff);
final Reader reader = new Reader(buff);
writer.start();
reader.start();
new Thread(new Runnable() {
public void run() {
long start = System.currentTimeMillis();
for (;;) {
// 等5秒鐘去中斷讀
if (System.currentTimeMillis() - start > 5000) {
System.out.println("不等了,嘗試中斷");
reader.interrupt();
break;
}
}
}
}).start();
}
}
interface IBuffer{
public void write();
public void read() throws InterruptedException;
}
class Buffer implements IBuffer{
private Object lock;
public Buffer() {
lock = this;
}
public void write() {
synchronized (lock) {
long startTime = System.currentTimeMillis();
System.out.println("開始往這個buff寫入資料…");
for (;;)// 模擬要處理很長時間
{
if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)
break;
}
System.out.println("終於寫完了");
}
}
public void read() {
synchronized (lock) {
System.out.println("從這個buff讀資料");
}
}
}
class BufferInterruptibly implements IBuffer{
private ReentrantLock lock = new ReentrantLock();
public void write() {
lock.lock();
try {
long startTime = System.currentTimeMillis();
System.out.println("開始往這個buff寫入資料…");
for (;;)// 模擬要處理很長時間
{
if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)
break;
}
System.out.println("終於寫完了");
} finally {
lock.unlock();
}
}
public void read() throws InterruptedException{
lock.lockInterruptibly();// 注意這裡,可以響應中斷
// lock.lock();// 注意這裡,不可以響應中斷
try {
System.out.println("從這個buff讀資料");
} finally {
lock.unlock();
}
}
}
class Writer extends Thread {
private IBuffer buff;
public Writer(IBuffer buff) {
this.buff = buff;
}
@Override
public void run() {
buff.write();
}
}
class Reader extends Thread {
private IBuffer buff;
public Reader(IBuffer buff) {
this.buff = buff;
}
@Override
public void run() {
try {
buff.read();
} catch (InterruptedException e) {
System.out.println("我不讀了");
}
System.out.println("讀結束");
}
}
1) 如果使用lock.lockInterruptibly();指定可以響應中斷,則輸出如下:
開始往這個buff寫入資料…
不等了,嘗試中斷
我不讀了
讀結束
則:獲取到中斷異常,執行中斷異常處理程式。
2) 如果使用lock.lock();指定不可以響應中斷,則輸出如下:
開始往這個buff寫入資料…
不等了,嘗試中斷
則:不能獲取到中斷異常,執行緒等待。
示例二:
package zmx.multithread.test.reentrantlock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class T2{
public static void main(String[] args){
Thread i1 = new Thread(new RunIt3());
Thread i2 = new Thread(new RunIt3());
i1.start();
i2.start();
i2.interrupt(); //中斷
}
}
class RunIt3 implements Runnable{
private static Lock lock = new ReentrantLock();
public void run(){
try{
//---------a--------------------------
//lock.lock();
lock.lockInterruptibly();
//lock.tryLock();
//lock.tryLock(5,TimeUnit.SECONDS);
System.out.println(Thread.currentThread().getName() + " running");
TimeUnit.SECONDS.sleep(10);
System.out.println(Thread.currentThread().getName() + " finished");
lock.unlock();
}catch (InterruptedException e){
System.out.println(Thread.currentThread().getName() + " interrupted");
}
}
}
如果a處是lock.lock(); 輸出:
Thread-0 running
(這裡休眠了10s)
Thread-0 finished
Thread-1 running
Thread-1 interrupted
============================
如果a處是lock.lockInterruptibly();輸出:
Thread-0 running
Thread-1 interrupted
(這裡休眠了10s)
Thread-0 finished
相關推薦
synchronized和ReentrantLock區別淺析
一、什麼是sychronized sychronized是java中最基本同步互斥的手段,可以修飾程式碼塊,方法,類. 在修飾程式碼塊的時候需要一個reference物件作為鎖的物件. 在修飾方法的時候預設是當前物件作為鎖的物件.
synchronized和ReentrantLock區別
sychronized 在java中,每一個物件有且僅有一個同步鎖。這也意味著,同步鎖是依賴於物件而存在。 當我們呼叫某物件的synchronized方法時,就獲取了該物件的同步鎖。例如,synchronized(obj)就獲取了“obj這個物件”的同步鎖。
synchronized和ReentrantLock的區別
sync ant 既然 word 變量 信息 log 死鎖 機制 synchronized和ReentrantLock的區別 synchronized是和if、else、for、while一樣的關鍵字,ReentrantLock是類,這是二者的本質區別。 既然Reentra
Synchronize和ReentrantLock區別
目錄介紹 1.Synchronize和ReentrantLock區別 1.1 相似點 1.2 區別 1.3 什麼是執行緒安全問題?如何理解 1.4 執行緒安全需要保證幾個基本特性 2.Synchronize在編譯時如何實現鎖機制 3.Reent
談談Synchrnized和ReentrantLock區別
今年參加校招筆試面試經常遇到的一個問題。 總的來說,ReentrantLock並不是一種替代內建加鎖的方法,而是當內建加鎖機制不適用時,作為一種可選擇的高階功能。與內建鎖不同的是,Lock提供了一種無條件的、可輪詢的、定時的以及可中斷的鎖獲取
Java併發--互斥同步--Java兩種鎖機制synchronized和ReentrantLock詳解
Java 提供了兩種鎖機制來控制多個執行緒對共享資源的互斥訪問,第一個是 JVM 實現的 synchronized,而另一個是 JDK 實現的 ReentrantLock。 synchronized 1. 同步一個程式碼塊 public void func() {
synchronized和volatile區別
synchronized和volatile區別 摘自《Java多執行緒程式設計核心技術》 關於synchronized和volatile的比較: 關鍵字volatile是執行緒同步的輕量級實現,所以volatile效能肯定比synchronized要好,並且只能修改變數,
JavaScript中const、var和let區別淺析
在JavaScript中有三種宣告變數的方式:var、let、const。下文給大家介紹js中三種定義變數的方式const, var, let的區別。 1.const定義的變數不可以修改,而且必須初始化。 ? 1 2 3 4 5 const
ES5和ES6區別淺析
前言 JavaScript一種動態型別、弱型別、基於原型的客戶端指令碼語言,用來給HTML網頁增加動態功能,具體概念不做過多的說明。這裡說一下JavaScript的主要組成: 【組成一】 ECMAScript ECMAScript是JS的核心,它規定了語言
【鎖機制】synchronized和ReentrantLock、鎖優化
java中的鎖的種類很多。目前對這部分知識點只是停留在瞭解的基礎上,就目前知識進行梳理,並長期補充。 java中鎖常用的為synchronized 和java.util.concurrent.Lock下的鎖。 下面對java中實現的鎖進行個人分析 Synchroni
Java中synchronized 和 ReentrantLock 有什麼不同?
Java在過去很長一段時間只能通過synchronized關鍵字來實現互斥,它有一些缺點。比如你不能擴充套件鎖之外的方法或者塊邊界,嘗試獲取鎖時不能中途取消等。Java 5 通過Lock
Synchronized與ReentrantLock區別總結(簡單粗暴,一目瞭然)
這篇文章是關於這兩個同步鎖的簡單總結比較,關於底層原始碼實現原理沒有過多涉及,後面會有關於這兩個同步鎖的底層原理篇幅去介紹。 相似點: 這兩種同步方式有很多相似之處,它們都是加鎖方式同步,而且都是阻塞式的同步,也就是說當如果一個執行緒獲得了物件鎖,進入了同步塊,其他訪問該
spark streaming、flink和storm區別淺析
1. 介紹 這三個計算框架常常被拿來比較。從我的角度來看,三者的比較可以分為兩類(mini-batches vs. strea
synchronized和鎖(ReentrantLock) 區別
區別一:API層面 synchronized使用 synchronized既可以修飾方法,也可以修飾程式碼塊。 synchronized修飾方法時,如下所示: //synchronized修飾一個方法時,這個方法叫同步方法。 public
jquery中prop()方法和attr()方法的區別淺析
clas ttr over dex idt pro query selected accesskey jquery1.6中新加了一個方法prop(),一直沒用過它,官方解釋只有一句話:獲取在匹配的元素集中的第一個元素的屬性值。 大家都知道有的瀏覽器只要寫disabled,c
synchronized 和 lock 的區別
lock interrupt 責任 結合 err 順序 導致 超時時間 定義 lock更靈活,可以自由定義多把鎖的加鎖解鎖順序(synchronized要按照先加的後解順序) 提供多種加鎖方案,lock 阻塞式, trylock 無阻塞式, lockInterruptily
Synchronized與ReentrantLock的區別
方式 ring syn 失敗 情況 public dem clas println java在編寫多線程程序時,為了保證線程安全,需要對數據同步,經常用到兩種同步方式就是Synchronized和重入鎖ReentrantLock。 相似點: 這兩種同步方式有
Synchronized和lock的區別和用法
等等 name log 括號 下使用 沒有 pos nal 輕量級 一、synchronized和lock的用法區別 (1)synchronized(隱式鎖):在需要同步的對象中加入此控制,synchronized可以加在方法上,也可以加在特定代碼塊中,括號中表示需要鎖的
java的兩種同步方式, Synchronized與ReentrantLock的區別
性能 避免 字節碼 數據 獲取對象 通過 finall 內核 構造函數 java在編寫多線程程序時,為了保證線程安全,需要對數據同步,經常用到兩種同步方式就是Synchronized和重入鎖ReentrantLock。 相似點: 這兩種同步方式有很多相似之
synchronized和Lock有什麼區別(不看後悔,看了必懂)
java語言中提供了兩種鎖機制來實現對某個共享資源的同步:synchronized和Lock.其中synchronized使用Object物件本身的notify,wait和notifyAll來實現執行緒之間的排程.而Lock可以使用Condition程序執行緒之間的排程 ①用法不同 sy