Java同步函數(shù)代碼詳解
/* 同步函數(shù) 當(dāng)函數(shù)中的代碼全部放在了同步代碼塊中,那么這個(gè)函數(shù)就是同步函數(shù) */ //同步函數(shù)的鎖是this鎖,this是一個(gè)引用,this指向的對(duì)象就是鎖 //下面證明一下同步函數(shù)的鎖就是this //創(chuàng)建兩個(gè)線程,一個(gè)在同步代碼塊中執(zhí)行,另一個(gè)在同步函數(shù)中執(zhí)行 //同步代碼塊用的鎖是obj,同步函數(shù)用的所是this //這就導(dǎo)致了兩個(gè)線程存在兩把鎖,會(huì)出現(xiàn)上次所說(shuō)的安全問(wèn)題,即出現(xiàn)錯(cuò)誤數(shù)據(jù) //只有兩個(gè)線程同時(shí)用一把鎖,才能解決多線程的安全問(wèn)題 class Ticket implements Runnable{ private int num = 50;//當(dāng)用靜態(tài)同步函數(shù)時(shí),需要將對(duì)象也改為靜態(tài)的 private Object obj = new Object(); //加一個(gè)flag標(biāo)記,一個(gè)線程得到CPU,判斷flag值 //如果是true,讓他在同步代碼塊中執(zhí)行,一旦進(jìn)去就出不來(lái)了,因?yàn)槿蝿?wù)代碼為死循環(huán) //否則讓他在同步函數(shù)中執(zhí)行 boolean flag = true; public void run(){ if(flag){ while(true){ //同步代碼塊,這里用的鎖是obj,與同步函數(shù)用不一樣的鎖,會(huì)出現(xiàn)安全問(wèn)題 //synchronized(obj){ //將鎖改為this,與同步函數(shù)為同一把鎖,就沒(méi)有問(wèn)題了 synchronized(this){//如果下面是靜態(tài)同步函數(shù),則應(yīng)該把this改為Ticket.class,同一把鎖 if(num>0){ //強(qiáng)制線程放棄CPU,睡眠的線程不會(huì)放棄鎖 try{Thread.sleep(20);}catch(InterruptedException e){e.printStackTrace();} System.out.println(Thread.currentThread().getName()+"...sale..."+num--);//1 } }//釋放鎖 } } else{ while(true){ fun(); } } } ////靜態(tài)函數(shù)進(jìn)內(nèi)存的時(shí)候不存在對(duì)象,但是存在其所屬類的字節(jié)碼文件對(duì)象,屬于Class類型的對(duì)象, //鎖必須是對(duì)象,字節(jié)碼文件,也是個(gè)對(duì)象,所以,靜態(tài)同步函數(shù)的鎖就是其所屬類的字節(jié)碼文件對(duì)象 //public static synchronized void fun(){//鎖為Ticket.class //這個(gè)函數(shù)的代碼都是同步代碼塊中的,所以這個(gè)函數(shù)可以修飾為同步的,即同步函數(shù) public synchronized void fun(){ if(num>0){ //強(qiáng)制線程放棄CPU,睡眠的線程不會(huì)放棄鎖 try{Thread.sleep(20);}catch(InterruptedException e){e.printStackTrace();} System.out.println(Thread.currentThread().getName()+"...sale..."+num--);//1 } } } class test{ public static void main(String[] args){ Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); //t1先啟動(dòng),但是他并不一定能搶到CPU,主線程依舊拿著CPU //主線程拿著CPU往下走,將flag改為了false,導(dǎo)致兩個(gè) //線程同時(shí)用的一個(gè)任務(wù)代碼,即一把鎖,不會(huì)出現(xiàn)安全問(wèn)題,所以,應(yīng)該在此處 //讓主線程進(jìn)入睡眠狀態(tài),主線程放棄CPU,然后t1立刻拿到CPU, //這樣t1就可以,在flag是true的情況下,進(jìn)入同步代碼塊中執(zhí)行 //所以t1用的就是obj鎖,然后主線程再拿上CPU,將flag改為false //t2拿上CPU時(shí),flag就為false,所以進(jìn)入的是同步函數(shù)中執(zhí)行, //同步函數(shù)用的鎖是this,兩把鎖,肯定會(huì)出現(xiàn)線程安全問(wèn)題,所以, //如果想解決安全問(wèn)題,將同步代碼塊的鎖,也改為this,即可解決 //讓主線程放棄CPU try{ Thread.sleep(20); }catch(InterruptedException e){ e.printStackTrace(); } t.flag = false; t2.start(); } }
總結(jié)
同步函數(shù)的鎖是this,靜態(tài)同步函數(shù)的鎖是他所屬類的字節(jié)碼文件對(duì)象。
以上就是本文關(guān)于Java同步函數(shù)代碼詳解的全部?jī)?nèi)容,希望對(duì)大家有所幫助,感興趣的朋友可以參閱:Java多線程ForkJoinPool實(shí)例詳解 Java通過(guò)賣票理解多線程 Java線程安全基礎(chǔ)概念解析等,感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
為什么Java中都不用a.equals(b)判斷對(duì)象相等
在面試中經(jīng)常會(huì)被問(wèn),a.equals(b)和“==”的區(qū)別,那么a.equals(b)能不能判斷對(duì)象相等,本文就來(lái)詳細(xì)的介紹一下2021-06-06Java實(shí)現(xiàn)的校驗(yàn)銀行卡功能示例
這篇文章主要介紹了Java實(shí)現(xiàn)的校驗(yàn)銀行卡功能,結(jié)合完整實(shí)例形式分析了java針對(duì)銀行卡類型、歸屬地等信息的判斷、讀取相關(guān)操作技巧,需要的朋友可以參考下2018-06-06Java數(shù)據(jù)結(jié)構(gòu)二叉樹(shù)難點(diǎn)解析
樹(shù)是一種重要的非線性數(shù)據(jù)結(jié)構(gòu),直觀地看,它是數(shù)據(jù)元素(在樹(shù)中稱為結(jié)點(diǎn))按分支關(guān)系組織起來(lái)的結(jié)構(gòu),很象自然界中的樹(shù)那樣。樹(shù)結(jié)構(gòu)在客觀世界中廣泛存在,如人類社會(huì)的族譜和各種社會(huì)組織機(jī)構(gòu)都可用樹(shù)形象表示2021-10-10SpringBoot整合Graylog做日志收集實(shí)現(xiàn)過(guò)程
這篇文章主要為大家介紹了SpringBoot整合Graylog做日志收集實(shí)現(xiàn)過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Java連接數(shù)據(jù)庫(kù)步驟解析(Oracle、MySQL)
本文主要介紹了Java連接Oracle數(shù)據(jù)庫(kù)和MySQL數(shù)據(jù)庫(kù)的步驟解析。具有很好的參考價(jià)值,需要的朋友一起來(lái)看下吧2016-12-12Java System.getProperty()-獲取系統(tǒng)參數(shù)案例詳解
這篇文章主要介紹了Java System.getProperty()-獲取系統(tǒng)參數(shù)案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08