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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

發布時間:2023/12/10 java 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是同步

  • 在上一篇0036 Java學習筆記-多線程-創建線程的三種方式示例代碼中,實現Runnable創建多條線程,輸出中的結果中會有錯誤,比如一張票賣了兩次,有的票沒賣的情況,因為線程對象被多條線程訪問,一條線程在執行一個循環的過程中被中斷,下一個線程則出現錯誤
  • 因此,線程任務中可能引起錯誤的地方應當被一次執行完畢

同步代碼塊

  • 用同步代碼塊改寫上面的代碼
package testpack;public class Test1 { public static void main(String[] args){ System.out.println("現在是主線程: "+Thread.currentThread()); System.out.println("下面新建兩個線程");A a=new A(500); new Thread(a,"線程A").start(); new Thread(a,"線程B").start();new Thread(a,"線程C").start();} } class A implements Runnable{private int tickets;A (int tick){tickets=tick;}private Object obj=new Object(); //同步監視器public void run() {synchronized(obj){ //同步代碼塊for (;tickets>0;tickets--) {System.out.println("當前線程:"+Thread.currentThread()+" 賣出第 "+tickets+" 張票。");try{Thread.sleep(1); //讓當前線程暫停1毫秒,其他線程也不能執行該同步代碼塊}catch(InterruptedException ex){ex.printStackTrace();}if (tickets==1){System.out.println("票已賣完,當前線程是: "+Thread.currentThread());}}}} }
  • 同步監視器,就是一個普通的對象,就像一把鎖,只有獲得了同步監視器的線程才能執行同步代碼塊。
  • 同步代碼塊執行一次完畢后,將會釋放鎖,接下來是這條線程拿到同步鎖,還是其他其他線程,則不一定,根據線程調度而定,但是在同步代碼塊執行過程中,不會被中斷,一個同步任務會被一次執行完畢

同步方法

  • 在同步代碼塊中,synchonized關鍵字在run()方法內部,修飾的是一段代碼,也可以用來修飾run()方法,也就是同步方法
  • synchronized不只可以修飾run()方法,還可以修飾其他方法,只要是需要一次同步完成的任務,然后再在run()方法中被調用
  • 同步方法中有一個隱式的同步監視器,就是this,也就是調用run()方法(或同步方法)的這個對象
  • 還是上面的實例,用同步方法改寫
package testpack;public class Test1 { public static void main(String[] args){ System.out.println("現在是主線程: "+Thread.currentThread()); System.out.println("下面新建兩個線程");A a=new A(500);new Thread(a,"線程A").start();new Thread(a,"線程B").start();new Thread(a,"線程C").start();} } class A implements Runnable{private int tickets;A (int tick){tickets=tick;}public synchronized void run() { //同步方法for (;tickets>0;tickets--) {System.out.println("當前線程:"+Thread.currentThread()+" 賣出第 "+tickets+" 張票。");try{Thread.sleep(1);}catch(InterruptedException ex){ex.printStackTrace();}if (tickets==1){System.out.println("票已賣完,當前線程是: "+Thread.currentThread());}}} }

釋放同步監視器

  • 當前線程的同步任務(同步方法、同步代碼塊)執行完畢
  • 在同步任務中,遇到break、return,終止了同步任務
  • 在同步任務中,出現Error、Exception等,導致同步任務結束
  • 在同步任務中,執行了同步監視器對象的wait()方法,則當前線程暫停,并釋放同步監視器
  • 不會釋放同步監視器的情況:
    • 同步任務中,調用Thread.sleep()、Thread.yield()方法來暫停當前線程的執行
    • 同步任務中,其他線程調用了該線程的suspend()方法將該線程掛起

同步鎖

  • 除了可以用new Object()和this作同步監視器往外,還可以定義專門的同步鎖,且功能更加強
  • Lock接口
    • ReentrantLock實現類
  • ReadWriteLock
    • ReentrantReadWriteLock實現類
    • ReentrantReadWriteLock.ReadLock
    • ReentrantReadWriteLock.WriteLock
  • StampedLock
  • 示例:用ReentrantLock改寫上面的代碼
package testpack;import java.util.concurrent.locks.ReentrantLock;public class Test1 { public static void main(String[] args){ System.out.println("現在是主線程: "+Thread.currentThread()); System.out.println("下面新建兩個線程");A a=new A(50);new Thread(a,"線程A").start();new Thread(a,"線程B").start();new Thread(a,"線程C").start();} } class A implements Runnable{private final ReentrantLock lock=new ReentrantLock(); //定義一個同步鎖private int tickets;A (int tick){tickets=tick;}public void run() {lock.lock(); //加鎖for (;tickets>0;tickets--) {System.out.println("當前線程:"+Thread.currentThread()+" 賣出第 "+tickets+" 張票。");if (tickets==1){System.out.println("票已賣完,當前線程是: "+Thread.currentThread());}}lock.unlock(); //釋放鎖} }

死鎖

  • 兩個線程各拿一把鎖,下一步運行都需要對方手里那把鎖,但都拿不到,則造成死鎖,程序不能繼續執行
package testpack; public class Test1 { public static void main(String[] args){ DeadLock dl=new DeadLock();new Thread(dl).start();dl.init();} } class DeadLock implements Runnable {A a=new A();B b=new B();public void init(){a.a1(b);System.out.println("進入主線程");}public void run(){b.b1(a);System.out.println("進入子線程");} } class A {public synchronized void a1(B b){System.out.println("當前線程是:"+Thread.currentThread().getName()+" ,正在執行a1()");try{Thread.sleep(10);}catch(InterruptedException ex){ex.printStackTrace();}System.out.println("當前線程是:"+Thread.currentThread().getName()+" ,準備調用b2()");b.b2(); //b2方法是同步方法,調用該方法要對調用的對象b加鎖}public synchronized void a2(){System.out.println("這是a2()方法");} } class B{public synchronized void b1(A a){System.out.println("當前線程是:"+Thread.currentThread().getName()+" ,正在執行b1()");try{Thread.sleep(10);}catch(InterruptedException ex){ex.printStackTrace();}System.out.println("當前線程是:"+Thread.currentThread().getName()+" ,準備調用a2()");a.a2(); //a2方法是同步方法,調用該方法要對調用的對象a加鎖}public synchronized void b2(){System.out.println("這是b2()方法");} }
  • 上面在調用a.a2()和b.b2()方法時,分別要對a對象和b對象加鎖,但這時,a、b對象的鎖都在對方手里,造成兩個線程阻塞

其他

  • 可變類的線程安全是以降低程序的運行效率為代價的
  • 不要對線程安全類的所有方法都進行同步,只對那些改變共享資源的方法進行同步
  • 如果一個類有單線程和多線程運行環境,那么應該提供兩種版本,就是StringBuilder(單線程)和StringBuffer(多線程)一樣

轉載于:https://www.cnblogs.com/sonng/p/6134444.html

總結

以上是生活随笔為你收集整理的0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁的全部內容,希望文章能夠幫你解決所遇到的問題。

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