1. 程式人生 > >synchronized和ReentrantLock區別淺析

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 

相關推薦

synchronizedReentrantLock區別淺析

一、什麼是sychronized        sychronized是java中最基本同步互斥的手段,可以修飾程式碼塊,方法,類.       在修飾程式碼塊的時候需要一個reference物件作為鎖的物件.       在修飾方法的時候預設是當前物件作為鎖的物件.   

synchronizedReentrantLock區別

sychronized 在java中,每一個物件有且僅有一個同步鎖。這也意味著,同步鎖是依賴於物件而存在。 當我們呼叫某物件的synchronized方法時,就獲取了該物件的同步鎖。例如,synchronized(obj)就獲取了“obj這個物件”的同步鎖。

synchronizedReentrantLock區別

sync ant 既然 word 變量 信息 log 死鎖 機制 synchronized和ReentrantLock的區別 synchronized是和if、else、for、while一樣的關鍵字,ReentrantLock是類,這是二者的本質區別。 既然Reentra

SynchronizeReentrantLock區別

目錄介紹 1.Synchronize和ReentrantLock區別 1.1 相似點 1.2 區別 1.3 什麼是執行緒安全問題?如何理解 1.4 執行緒安全需要保證幾個基本特性 2.Synchronize在編譯時如何實現鎖機制 3.Reent

談談SynchrnizedReentrantLock區別

  今年參加校招筆試面試經常遇到的一個問題。     總的來說,ReentrantLock並不是一種替代內建加鎖的方法,而是當內建加鎖機制不適用時,作為一種可選擇的高階功能。與內建鎖不同的是,Lock提供了一種無條件的、可輪詢的、定時的以及可中斷的鎖獲取

Java併發--互斥同步--Java兩種鎖機制synchronizedReentrantLock詳解

Java 提供了兩種鎖機制來控制多個執行緒對共享資源的互斥訪問,第一個是 JVM 實現的 synchronized,而另一個是 JDK 實現的 ReentrantLock。 synchronized 1. 同步一個程式碼塊 public void func() {

synchronizedvolatile區別

synchronized和volatile區別 摘自《Java多執行緒程式設計核心技術》 關於synchronized和volatile的比較: 關鍵字volatile是執行緒同步的輕量級實現,所以volatile效能肯定比synchronized要好,並且只能修改變數,

JavaScript中const、varlet區別淺析

在JavaScript中有三種宣告變數的方式:var、let、const。下文給大家介紹js中三種定義變數的方式const, var, let的區別。 1.const定義的變數不可以修改,而且必須初始化。 ? 1 2 3 4 5 const

ES5ES6區別淺析

前言 JavaScript一種動態型別、弱型別、基於原型的客戶端指令碼語言,用來給HTML網頁增加動態功能,具體概念不做過多的說明。這裡說一下JavaScript的主要組成: 【組成一】 ECMAScript ECMAScript是JS的核心,它規定了語言

【鎖機制】synchronizedReentrantLock、鎖優化

java中的鎖的種類很多。目前對這部分知識點只是停留在瞭解的基礎上,就目前知識進行梳理,並長期補充。 java中鎖常用的為synchronized 和java.util.concurrent.Lock下的鎖。 下面對java中實現的鎖進行個人分析 Synchroni

Java中synchronized ReentrantLock 有什麼不同?

        Java在過去很長一段時間只能通過synchronized關鍵字來實現互斥,它有一些缺點。比如你不能擴充套件鎖之外的方法或者塊邊界,嘗試獲取鎖時不能中途取消等。Java 5 通過Lock

SynchronizedReentrantLock區別總結(簡單粗暴,一目瞭然)

這篇文章是關於這兩個同步鎖的簡單總結比較,關於底層原始碼實現原理沒有過多涉及,後面會有關於這兩個同步鎖的底層原理篇幅去介紹。 相似點: 這兩種同步方式有很多相似之處,它們都是加鎖方式同步,而且都是阻塞式的同步,也就是說當如果一個執行緒獲得了物件鎖,進入了同步塊,其他訪問該

spark streaming、flinkstorm區別淺析

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

SynchronizedReentrantLock區別

方式 ring syn 失敗 情況 public dem clas println java在編寫多線程程序時,為了保證線程安全,需要對數據同步,經常用到兩種同步方式就是Synchronized和重入鎖ReentrantLock。 相似點: 這兩種同步方式有

Synchronizedlock的區別用法

等等 name log 括號 下使用 沒有 pos nal 輕量級 一、synchronized和lock的用法區別 (1)synchronized(隱式鎖):在需要同步的對象中加入此控制,synchronized可以加在方法上,也可以加在特定代碼塊中,括號中表示需要鎖的

java的兩種同步方式, SynchronizedReentrantLock區別

性能 避免 字節碼 數據 獲取對象 通過 finall 內核 構造函數 java在編寫多線程程序時,為了保證線程安全,需要對數據同步,經常用到兩種同步方式就是Synchronized和重入鎖ReentrantLock。 相似點: 這兩種同步方式有很多相似之

synchronizedLock有什麼區別(不看後悔,看了必懂)

java語言中提供了兩種鎖機制來實現對某個共享資源的同步:synchronized和Lock.其中synchronized使用Object物件本身的notify,wait和notifyAll來實現執行緒之間的排程.而Lock可以使用Condition程序執行緒之間的排程 ①用法不同 sy