同步鎖Synchronized與Lock的區別?


 synchronizedLock兩者區別:

  1:Lock是一個接口,而Synchronized關鍵字

  2:Synchronized會自動釋放鎖,而Lock必須手動釋放鎖

  3:Lock可以讓等待鎖的線程響應中斷,而Synchronized不會,線程會一直等待下去。

  4:通過Lock可以知道線程有沒有拿到鎖,而Synchronized不能。

  5:Lock能提高多個線程讀操作的效率。

  6:Synchronized鎖住類、方法和代碼塊,而Lock塊范圍內

 

  /**
  * synchronized:在需要同步的對象中加入此控制,synchronized可以加在方法上,也可以加在特定代碼塊中,括號中表示需要鎖的對象。
  * lock:需要顯示指定起始位置和終止位置。一般使用ReentrantLock類做為鎖,多個線程中必須要使用一個ReentrantLock類
  * 作為對象才能保證鎖的生效。
  * 且在加鎖和解鎖處需要通過lock()和unlock()顯示指出。所以一般會在finally塊中寫unlock()以防死鎖。
  *
  * synchronized原始采用的是CPU悲觀鎖機制,即線程獲得的是獨占鎖。獨占鎖意味着其他線程只能依靠阻塞來等待線程釋放鎖。
  * 而在CPU轉換線程阻塞時會引起線程上下文切換,當有很多線程競爭鎖的時候,會引起CPU頻繁的上下文切換導致效率很低
  * Lock用的是樂觀鎖方式。所謂樂觀鎖就是,每次不加鎖而是假設沒有沖突而去完成某項操作,
  * 如果因為沖突失敗就重試,直到成功為止。
  * 樂觀鎖實現的機制就是CAS操作(Compare and Swap)。我們可以進一步研究ReentrantLock的源代碼,
  * 會發現其中比較重要的獲得鎖的一個方法是compareAndSetState。這里其實就是調用的CPU提供的特殊指令
  */

再看具體代碼小例子:

package  com.cn.test.thread.lock;
import  java.util.concurrent.locks.Lock;
import  java.util.concurrent.locks.ReentrantLock;
 
public class  LockTest {
     private  Lock lock =  new  ReentrantLock();
     /*
     * 使用完畢釋放后其他線程才能獲取鎖
     */
     public void  lockTest(Thread thread) {
 
         lock.lock(); //獲取鎖
         try  {
             System.out.println( "線程" +thread.getName() +  "獲取當前鎖" );  //打印當前鎖的名稱
             Thread.sleep( 2000 ); //為看出執行效果,是線程此處休眠2秒
         catch  (Exception e) {
             System.out.println( "線程" +thread.getName() +  "發生了異常釋放鎖" );
         } finally  {
             System.out.println( "線程" +thread.getName() +  "執行完畢釋放鎖" );
             lock.unlock();  //釋放鎖
         }
     }
     
     public static void  main(String[] args) {
 
         LockTest lockTest =  new  LockTest();
         //聲明一個線程 “線程一”
         Thread thread1 =  new  Thread( new  Runnable() {
             @Override
             public void  run() {
                 lockTest.lockTest(Thread.currentThread());
             }
         },  "thread1" );
         //聲明一個線程 “線程二”
         Thread thread2 =  new  Thread( new  Runnable() {
 
             @Override
             public void  run() {
                 lockTest.lockTest(Thread.currentThread());
             }
         },  "thread2" );
         // 啟動2個線程
         thread2.start();
         thread1.start();
 
     }
}

執行結果:

 

package com.cn.test.thread.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {
    private Lock lock = new ReentrantLock();
    
    /*
     * 嘗試獲取鎖 tryLock() 它表示用來嘗試獲取鎖,如果獲取成功,則返回true,如果獲取失敗(即鎖已被其他線程獲取),則返回false
     */
    public void tryLockTest(Thread thread) {
if(lock.tryLock()) { //嘗試獲取鎖 try { System.out.println("線程"+thread.getName() + "獲取當前鎖"); //打印當前鎖的名稱 Thread.sleep(2000);//為看出執行效果,是線程此處休眠2秒 } catch (Exception e) { System.out.println("線程"+thread.getName() + "發生了異常釋放鎖"); }finally { System.out.println("線程"+thread.getName() + "執行完畢釋放鎖"); lock.unlock(); //釋放鎖 } }else{ System.out.println("我是線程"+Thread.currentThread().getName()+"當前鎖被別人占用,我無法獲取"); } } public static void main(String[] args) {
LockTest lockTest = new LockTest();  //聲明一個線程 “線程一” Thread thread1 = new Thread(new Runnable() { @Override public void run() { lockTest.tryLockTest(Thread.currentThread()); } }, "thread1"); //聲明一個線程 “線程二” Thread thread2 = new Thread(new Runnable() { @Override public void run() { lockTest.tryLockTest(Thread.currentThread()); } }, "thread2"); // 啟動2個線程 thread2.start(); thread1.start(); } }

執行結果:

 

package com.cn.test.thread.lock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest {
    private Lock lock = new ReentrantLock();
public void tryLockParamTest(Thread thread) throws InterruptedException {
if(lock.tryLock(3000, TimeUnit.MILLISECONDS)) { //嘗試獲取鎖 獲取不到鎖,就等3秒,如果3秒后還是獲取不到就返回false try { System.out.println("線程"+thread.getName() + "獲取當前鎖"); //打印當前鎖的名稱 Thread.sleep(4000);//為看出執行效果,是線程此處休眠2秒 } catch (Exception e) { System.out.println("線程"+thread.getName() + "發生了異常釋放鎖"); }finally { System.out.println("線程"+thread.getName() + "執行完畢釋放鎖"); lock.unlock(); //釋放鎖 } }else{ System.out.println("我是線程"+Thread.currentThread().getName()+"當前鎖被別人占用,等待3s后仍無法獲取,放棄"); } } public static void main(String[] args) {
LockTest lockTest = new LockTest(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { try { lockTest.tryLockParamTest(Thread.currentThread()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }, "thread1"); //聲明一個線程 “線程二” Thread thread2 = new Thread(new Runnable() { @Override public void run() { try { lockTest.tryLockParamTest(Thread.currentThread()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }, "thread2"); // 啟動2個線程 thread2.start(); thread1.start(); } }

執行結果:

因為此時線程1休眠了4秒,線程2等待了3秒還沒有獲取到就放棄獲取鎖了,執行結束

將方法中的 Thread.sleep(4000)改為Thread.sleep(2000)執行結果如下:

因為此時線程1休眠了2秒,線程2等待了3秒的期間線程1釋放了鎖,此時線程2獲取到鎖,線程2就可以執行了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM