日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java中实现同步的两种方式:syschronized和lock的区别和联系

發布時間:2024/2/28 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java中实现同步的两种方式:syschronized和lock的区别和联系 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自?http://www.cnblogs.com/xiohao/p/4151408.html

? Lock是java.util.concurrent.locks包下的接口,Lock?實現提供了比使用synchronized?方法和語句可獲得的更廣泛的鎖定操作,它能以更優雅的方式處理線程同步問題,我們拿Java線程(二)中的一個例子簡單的實現一下和sychronized一樣的效果,代碼如下:

?

[java]?view plaincopy

?

  • public?class?LockTest?{??
  • ????public?static?void?main(String[]?args)?{??
  • ????????final?Outputter1?output?=?new?Outputter1();??
  • ????????new?Thread()?{??
  • ????????????public?void?run()?{??
  • ????????????????output.output("zhangsan");??
  • ????????????};??
  • ????????}.start();????????
  • ????????new?Thread()?{??
  • ????????????public?void?run()?{??
  • ????????????????output.output("lisi");??
  • ????????????};??
  • ????????}.start();??
  • ????}??
  • }??
  • class?Outputter1?{??
  • ????private?Lock?lock?=?new?ReentrantLock();//?鎖對象??
  • ????public?void?output(String?name)?{??
  • ????????//?TODO?線程輸出方法??
  • ????????lock.lock();//?得到鎖??
  • ????????try?{??
  • ????????????for(int?i?=?0;?i?<?name.length();?i++)?{??
  • ????????????????System.out.print(name.charAt(i));??
  • ????????????}??
  • ????????}?finally?{??
  • ????????????lock.unlock();//?釋放鎖??
  • ????????}??
  • ????}??
  • }??
  • ? ? ? ? 這樣就實現了和sychronized一樣的同步效果,需要注意的是,用sychronized修飾的方法或者語句塊在代碼執行完之后鎖自動釋放,而用Lock需要我們手動釋放鎖,所以為了保證鎖最終被釋放(發生異常情況),要把互斥區放在try內,釋放鎖放在finally內。

    ?

    ? ? ? ? 如果說這就是Lock,那么它不能成為同步問題更完美的處理方式,下面要介紹的是讀寫鎖(ReadWriteLock),我們會有一種需求,在對數據進行讀寫的時候,為了保證數據的一致性和完整性,需要讀和寫是互斥的,寫和寫是互斥的,但是讀和讀是不需要互斥的,這樣讀和讀不互斥性能更高些,來看一下不考慮互斥情況的代碼原型:

    ?

    [java]?view plaincopy

    ?

  • public?class?ReadWriteLockTest?{??
  • ????public?static?void?main(String[]?args)?{??
  • ????????final?Data?data?=?new?Data();??
  • ????????for?(int?i?=?0;?i?<?3;?i++)?{??
  • ????????????new?Thread(new?Runnable()?{??
  • ????????????????public?void?run()?{??
  • ????????????????????for?(int?j?=?0;?j?<?5;?j++)?{??
  • ????????????????????????data.set(new?Random().nextInt(30));??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}).start();??
  • ????????}?????????
  • ????????for?(int?i?=?0;?i?<?3;?i++)?{??
  • ????????????new?Thread(new?Runnable()?{??
  • ????????????????public?void?run()?{??
  • ????????????????????for?(int?j?=?0;?j?<?5;?j++)?{??
  • ????????????????????????data.get();??
  • ????????????????????}??
  • ????????????????}??
  • ????????????}).start();??
  • ????????}??
  • ????}??
  • }??
  • class?Data?{??????
  • ????private?int?data;//?共享數據??????
  • ????public?void?set(int?data)?{??
  • ????????System.out.println(Thread.currentThread().getName()?+?"準備寫入數據");??
  • ????????try?{??
  • ????????????Thread.sleep(20);??
  • ????????}?catch?(InterruptedException?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????????this.data?=?data;??
  • ????????System.out.println(Thread.currentThread().getName()?+?"寫入"?+?this.data);??
  • ????}?????
  • ????public?void?get()?{??
  • ????????System.out.println(Thread.currentThread().getName()?+?"準備讀取數據");??
  • ????????try?{??
  • ????????????Thread.sleep(20);??
  • ????????}?catch?(InterruptedException?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????????System.out.println(Thread.currentThread().getName()?+?"讀取"?+?this.data);??
  • ????}??
  • }??
  • ? ? ? ? 部分輸出結果:

    ?

    ?

    [java]?view plaincopy

    ?

  • Thread-1準備寫入數據??
  • Thread-3準備讀取數據??
  • Thread-2準備寫入數據??
  • Thread-0準備寫入數據??
  • Thread-4準備讀取數據??
  • Thread-5準備讀取數據??
  • Thread-2寫入12??
  • Thread-4讀取12??
  • Thread-5讀取5??
  • Thread-1寫入12??
  • ? ? ? ? 我們要實現寫入和寫入互斥,讀取和寫入互斥,讀取和讀取互斥,在set和get方法加入sychronized修飾符:

    ?

    ?

    [java]?view plaincopy

    ?

  • public?synchronized?void?set(int?data)?{...}??????
  • public?synchronized?void?get()?{...}??
  • ? ? ? ? 部分輸出結果:

    [java]?view plaincopy

    ?

  • Thread-0準備寫入數據??
  • Thread-0寫入9??
  • Thread-5準備讀取數據??
  • Thread-5讀取9??
  • Thread-5準備讀取數據??
  • Thread-5讀取9??
  • Thread-5準備讀取數據??
  • Thread-5讀取9??
  • Thread-5準備讀取數據??
  • Thread-5讀取9??
  • ? ? ? ? 我們發現,雖然寫入和寫入互斥了,讀取和寫入也互斥了,但是讀取和讀取之間也互斥了,不能并發執行,效率較低,用讀寫鎖實現代碼如下:

    ?

    ?

    [java]?view plaincopy

    ?

  • class?Data?{??????
  • ????private?int?data;//?共享數據??
  • ????private?ReadWriteLock?rwl?=?new?ReentrantReadWriteLock();?????
  • ????public?void?set(int?data)?{??
  • ????????rwl.writeLock().lock();//?取到寫鎖??
  • ????????try?{??
  • ????????????System.out.println(Thread.currentThread().getName()?+?"準備寫入數據");??
  • ????????????try?{??
  • ????????????????Thread.sleep(20);??
  • ????????????}?catch?(InterruptedException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ????????????this.data?=?data;??
  • ????????????System.out.println(Thread.currentThread().getName()?+?"寫入"?+?this.data);??
  • ????????}?finally?{??
  • ????????????rwl.writeLock().unlock();//?釋放寫鎖??
  • ????????}??
  • ????}?????
  • ????public?void?get()?{??
  • ????????rwl.readLock().lock();//?取到讀鎖??
  • ????????try?{??
  • ????????????System.out.println(Thread.currentThread().getName()?+?"準備讀取數據");??
  • ????????????try?{??
  • ????????????????Thread.sleep(20);??
  • ????????????}?catch?(InterruptedException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}??
  • ????????????System.out.println(Thread.currentThread().getName()?+?"讀取"?+?this.data);??
  • ????????}?finally?{??
  • ????????????rwl.readLock().unlock();//?釋放讀鎖??
  • ????????}??
  • ????}??
  • }??
  • ?

    ? ? ? ? 部分輸出結果:

    ?

    [java]?view plaincopy

    ?

  • Thread-4準備讀取數據??
  • Thread-3準備讀取數據??
  • Thread-5準備讀取數據??
  • Thread-5讀取18??
  • Thread-4讀取18??
  • Thread-3讀取18??
  • Thread-2準備寫入數據??
  • Thread-2寫入6??
  • Thread-2準備寫入數據??
  • Thread-2寫入10??
  • Thread-1準備寫入數據??
  • Thread-1寫入22??
  • Thread-5準備讀取數據??
  • ? ? ? ? 從結果可以看出實現了我們的需求,這只是鎖的基本用法,鎖的機制還需要繼續深入學習。

    ? ? ? ? 本文來自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/7461369,轉載請注明。

    ?

    ?

    ?

    ?

    在java中有兩種方式實現原子性操作(即同步操作):
    1)使用同步關鍵字synchronized
    2)使用lock鎖機制其中也包括相應的讀寫鎖


    package com.xiaohao.test;

    import java.util.Random;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;

    public class Test {
    public static void main(String[] args) {
    final LockTest lock=new LockTest();?
    //輸出張三?
    new Thread(){
    public void run(){
    lock.test("張三張三張三張三張三張三張三張三張三張三");
    }?
    }.start();

    //輸出李四
    new Thread(){
    public void run(){
    lock.test("李四李四李四李四李四李四李四李四李四李四");System.out.println?
    ("\n---------------------------------------------------------------");
    }
    }.start();


    //---------------------------------------------------------------
    //模擬寫入數據的
    for (int i = 0; i < 3; i++) {?
    new Thread(){?
    public void run() {?
    for (int j = 0; j < 5; j++) {?
    // lock.set(new Random().nextInt(30));?
    lock.set2(new Random().nextInt(30));

    }?
    }?
    }.start();

    }
    //模擬讀取數據的
    for (int i = 0; i < 3; i++) {?
    new Thread(){?
    public void run() {?
    for (int j = 0; j < 5; j++) {?
    // lock.get();?
    lock.get2();?
    }?
    }?
    }.start();
    }


    }
    }

    class LockTest{
    private Lock lock=new ReentrantLock(); //創建普通的鎖
    private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();//創建讀寫鎖
    private int data;// 共享數據?


    //實現同步的方法一 使用同步關鍵字 synchronized
    public synchronized void test(String name){
    //下面的相關操作是一個原子性的操作
    // lock.lock();// 得到鎖?
    try {?
    for(int i = 0; i < name.length(); i++) {?
    System.out.print(name.charAt(i));?
    }?
    } finally {?
    // lock.unlock();// 釋放鎖?
    }?
    }




    //實現同步的方法二 使用lock鎖機制
    public void test2(String name){
    //下面的相關操作是一個原子性的操作
    lock.lock();// 得到鎖?
    try {?
    for(int i = 0; i < name.length(); i++) {?
    System.out.print(name.charAt(i));?
    }?
    } finally {?
    lock.unlock();// 釋放鎖?
    }?
    }


    //使用set方法模擬寫入數據?
    //使用 synchronized 實現了讀讀,寫寫,讀寫之間的互斥 ,但讀讀之間的互斥是沒有什么必要的
    public synchronized void set(int data){
    System.out.println(Thread.currentThread().getName() + "準備寫入數據");?
    try {?
    Thread.sleep(20);?
    } catch (InterruptedException e) {?
    e.printStackTrace();?
    }?
    this.data = data;?
    System.out.println(Thread.currentThread().getName() + "寫入" + this.data);?
    }

    //使用get方法模擬讀取數據
    //使用 synchronized 實現了讀讀,寫寫,讀寫之間的互斥 ,但讀讀之間的互斥是沒有什么必要的
    public synchronized void get() {?
    System.out.println(Thread.currentThread().getName() + "準備讀取數據");?
    try {?
    Thread.sleep(20);?
    } catch (InterruptedException e) {?
    e.printStackTrace();?
    }?
    System.out.println(Thread.currentThread().getName() + "讀取" + this.data);?
    }?


    //使用set方法模擬寫入數據?
    //使用 讀寫鎖實現了寫寫,讀寫之間的互斥 ,但讀讀之間的互斥是沒有什么必要的
    public void set2(int data){
    readWriteLock.writeLock().lock();//獲取寫入鎖
    try{
    System.out.println(Thread.currentThread().getName() + "準備寫入數據");?
    try {?
    Thread.sleep(20);?
    } catch (InterruptedException e) {?
    e.printStackTrace();?
    }?
    this.data = data;?
    System.out.println(Thread.currentThread().getName() + "寫入" + this.data);?
    }
    finally{
    readWriteLock.writeLock().unlock();
    }
    }


    //使用get方法模擬讀取數據
    //使用 讀寫鎖實現了寫寫,讀寫之間的互斥 ,但讀讀之間的互斥是沒有什么必要的
    public void get2() {?
    //獲取相應的讀鎖
    readWriteLock.readLock().lock();
    try{
    System.out.println(Thread.currentThread().getName() + "準備讀取數據");?
    try {?
    Thread.sleep(20);?
    } catch (InterruptedException e) {?
    e.printStackTrace();?
    }?
    System.out.println(Thread.currentThread().getName() + "讀取" + this.data);?
    }
    finally{
    // 釋放相應的寫鎖
    readWriteLock.readLock().unlock();
    }
    }?

    }

    ?

    ?

    ?

    線程同步經典版:

    package com.xiaohao.test;

    import java.util.concurrent.locks.ReentrantReadWriteLock;

    public class Test2{

    ?public static void main(String[] args){

    ??final LockTest2 lockTest=new LockTest2(); ?

    ?for(int i=0;i<3;i++) ??{ ???

    new Thread(){ ???????

    ? public void run(){?????? ??

    ??????? try { ?

    ?? ????? for (int j = 0; j < 3; j++) {? ???

    ??????? ?lockTest.setValue(); ???

    ????? } ???} catch (InterruptedException e) { ?

    ???// TODO Auto-generated catch block ????e.printStackTrace(); ?

    ??} ??????

    ? ? } ?????

    ??? }.start(); ?

    ?} ?

    ?for(int i=0;i<3;i++) ??{ ?

    ??????? new Thread(){ ????

    ??? ? public void run(){?????? ?? ??? ??

    ?? try { ??? ????

    ? for (int j = 0; j < 3; j++) {?

    ????lockTest.getValue(); ??? ??

    ??? } ???

    } catch (InterruptedException e)

    { ????// TODO Auto-generated catch block ????e.printStackTrace(); ???} ??????

    ? ? } ??????

    ?? }.start(); ?

    }????

    ?} ?

    }

    class? LockTest2 {

    ?int data=0; ?

    ReentrantReadWriteLock lock= new ReentrantReadWriteLock();// 鎖對象

    ? ?public void setValue() throws InterruptedException{ ??

    lock.writeLock().lock(); ?

    ?System.out.println("正在使用寫鎖......"); ???

    data=(int) (Math.random()*10); ??

    ?System.out.println("正在寫入:"+data); ??

    ?Thread.sleep(500); ?

    ?System.out.println("寫鎖調用完畢---------------------------");

    ??lock.writeLock().unlock(); ?} ?

    ?public void getValue() throws InterruptedException{

    ??lock.readLock().lock(); ????

    System.out.println("正在使用讀鎖...........................................");

    ???System.out.println("正在讀入:"+data); ???Thread.sleep(500);

    ??System.out.println("讀鎖調用完畢......");

    ??lock.readLock().unlock(); ?

    }

    }

    ?

    ?**** 當一個線程進入了一個對象是的synchronized方法,那么其它線程還能掉否調用此對象的其它方法?

    ????????這個問題需要分幾種情況進行討論。

    ????? 1)查看其它方法是否使用了同步關鍵字(synchronized)修飾,如果沒有的話就可以調用相關的方法。

    ????? 2)在當前synchronized方法中是否調用了wait方法,如果調用了,則對應的鎖已經釋放,可以訪問了。

    ????? 3)如果其它方法也使用synchronized修飾,并且當前同步方法中沒有調用wait方法的話,這樣是不允許訪問的。

    ????? 4)如果其它方法是靜態方法的話,由于靜態方法和對象是扯不上什么關系,對于靜態同步方法而言,其對應的同步監視器為當前類的字節碼

    ?????????? 所以肯定可以訪問的了。

    總結

    以上是生活随笔為你收集整理的java中实现同步的两种方式:syschronized和lock的区别和联系的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。