?? ?? ????: java ?? ????
??? ?? ??
- 1. ?? ?? ??
- 3. ???? ?? ??
- ???? ??
- ????? ? ?? ?? ??? ?? ??? ????
- ??? ???? ??? ??
- ??
- ??? ??
- 4. ?? ? ??? ?? ??. ?? ??
6. ?? ???- 7. ???? ???? ? ?? ??: ?? ?? ????? ??
- 9. ?? ???? ?? ? ?? ???
- 10.
- 1. ??? ?? ??
- 2.1. ??? ? ?????? ?? ???? ?? ????? ?? ???? ??? ??? ??? ?? ??? ??, ??? ?? ?? ? ??? ??? ??????. ??? ? ??? ??? ??? ????.
- ??? ??? ?? ??? ???? ????? ????? ???? ????? ??? ?? ??? ???. ? ???? ? ?? ????? ?? ???? ???? ???? ?????. (??: *****) 2.2. ?? ??? ?? ???? ???? ?? ??? ???? ??? ??????
?? ?? ??:
??? 1: ?? ??? ???.??? 2: ?? ???? ????.
??? 3: ?? ???? ?? ??? ????.
??
?? ? ?? ??? ???? ??? ?? ??? ?????.
2.3. ??? ?? ??? ???? ??? ?????? ?? ??? ?? ???? ?? ???? ?? ? ???? ??? ?? ??? ?? ??? ?????. ? ??? ???? ??? ??????
??
???? ?? ?? ????. (??? ? ????.)
? ??? ??? ???? ??? ?? ??? ?????. ??? ????? ??? ??? ??????? ???.
???? ??? ??? ????.
??? ???? ??? ???? ??? ??? ? ??? ???? ??? ?? ???? ??? ?? ?????
. ????? ?? ??? ???? ??? ??????
??
"??? ??? ????"? ?????.
???? ???? ???? ???? ?? ?? ?????. ???? ???? ??? ???? ??? ?????. ??? ??? ??? ? ???? ?? ???? ? ????. ???? ???? ?? ???? ????. 2.4. ??? ???? ???? ?? ? ?? ?? ??? ?????.
??? ????? ??:
? ??? t1? ??? t2? ?? ?? ??? ?????. t1? t2? ????, t2? t1? ???? ? ??? ????. ??? ???? ???? ? ????? ??? ??? ????? ????? ???. ???, ?? ??? ???(? ?? ???)
?? ????? ??:
??? ??? t1? ??? t2? ??? t1? ??? ? t2? ??? ??? ??? ???? ???. ?, t2 ???? ??? ???? t1 ???? ??? ?? ??? ???? ??, ? ??? ?? ?? ??? ???? ?? ??? ????? ?????. ? ??????. ???? ??? ?? ???? ????.
2. ?? ?? ??
package?ThreadSafe;public?class?Account?{ //賬號(hào) private?String?actno; //余額 private?double?balance; public?Account(String?actno,?double?balance)?{ super(); this.actno?=?actno; this.balance?=?balance; } public?String?getActno()?{ return?actno; } public?void?setActno(String?actno)?{ this.actno?=?actno; } public?double?getBalance()?{ return?balance; } public?void?setBalance(double?balance)?{ this.balance?=?balance; } //取款的方法 public?void?withdraw(double?money){ //t1和t2并發(fā)執(zhí)行這個(gè)方法(t1和t2是兩個(gè)棧?,兩個(gè)棧操作堆中同一個(gè)對(duì)象) //取款之前的余額 double?before=this.getBalance(); //取款之后的余額 double?after=before-money; //模擬一下網(wǎng)絡(luò)延遲,會(huì)出現(xiàn)問(wèn)題 try?{ Thread.sleep(1000); }?catch?(InterruptedException?e)?{ //?TODO?Auto-generated?catch?block e.printStackTrace(); } //更新余額 //思考:t1執(zhí)行到這里了,但還沒(méi)有來(lái)得及執(zhí)行這行代碼,t2線程進(jìn)來(lái)withdraw方法了,此時(shí)一定出問(wèn)題 this.setBalance(after); }}AccountThread類(lèi)public?class?AccountThread?extends?Thread{ //兩個(gè)線程必須共享一個(gè)賬戶對(duì)象 private?Account?act; //通過(guò)構(gòu)造方法傳遞過(guò)來(lái)賬戶對(duì)象 public?AccountThread(Account?act)?{ this.act?=?act; } @Override public?void?run()?{ //假設(shè)取款5000 double?money=5000; //多線程執(zhí)行這個(gè)方法 act.withdraw(money); System.out.println(Thread.currentThread().getName()+"賬戶"+act.getActno()+"取款成功"+act.getBalance()); }}??? ???
public?class?Test?{ public?static?void?main(String[]?args)?{ //創(chuàng)建賬戶對(duì)象 Account?act=new?Account("act-001",10000); //創(chuàng)建兩個(gè)線程 Thread?t1=new?AccountThread(act); Thread?t2=new?AccountThread(act); t1.setName("t1"); t2.setName("t2"); //啟動(dòng)兩個(gè)線程執(zhí)行 t1.start(); t2.start(); }}
3. ??? ?? ?? ??? ???? ?? ??
//? ???? ??? ?? ?? ??? ?? ? ?? ???? ??? ? ????
/*??? ??? ????? ??? ???(){
/ /??? ??? ?? ??.
} ??? ? ?? ?? ??? ???? ?? ?????.
? ???? ?? ??? ???? ???? ?? ?? ????? ????? ???.
() ??? ??? ?????? ?????? ???? ?? ????.
5?? ??? t1, t2, t3, t4, t5? ??? ?????.
t1 t2 t3? ???? ???? ??? t4 t5? ???? ??? ??? ????. ??? ?? ???? ()? ??? ??? t1 t2 t3? ???? ??? ????? ? ??? t4 t5? ???? ????
?? ?? ??? ?? ?????
?? ??? ???? ?? ?? ????? ??? ??? ? ??? ?? ??? ????. ???? ???? ??? ????
synchronized(this){ double?before=this.getBalance(); double?after=before-money; try?{ Thread.sleep(1000); }?catch?(InterruptedException?e)?{ //?TODO?Auto-generated?catch?block e.printStackTrace(); } this.setBalance(after); }
在java語(yǔ)言中,任何對(duì)象都有一把鎖,其實(shí)這把鎖就是一個(gè)標(biāo)記,(只是把它叫做鎖)
100個(gè)對(duì)象,100個(gè)鎖,1個(gè)對(duì)象1把鎖。
以上代碼的執(zhí)行原理是什么呢?
1.假設(shè)t1和t2線程并發(fā),開(kāi)始執(zhí)行以上代碼的時(shí)候,肯定有一個(gè)先一個(gè)后,
2.假設(shè)t1先執(zhí)行了,遇到了synchronized,這個(gè)時(shí)候自動(dòng)找后面共享對(duì)象的對(duì)象鎖,找到之后,并占有這把鎖,然后執(zhí)行同步代碼塊中的程序,在程序執(zhí)行過(guò)程中一直都占有這把鎖,直到同步代碼塊執(zhí)行結(jié)束,這把鎖才會(huì)釋放。
3.假設(shè)t1已經(jīng)占有這把鎖,此時(shí)t2也遇到synchronized關(guān)鍵字,也會(huì)去占有后面共享對(duì)象的這把鎖,結(jié)果這把鎖被t1占有,t2只能在同步代碼塊外邊等待t1的結(jié)束,直到t1把同步代碼塊執(zhí)行結(jié)束了,t1會(huì)歸還這把鎖,此時(shí)t2終于等到這把鎖,然后t2占有這把鎖之后,進(jìn)入同步代碼塊執(zhí)行程序。
這樣就達(dá)到了線程排隊(duì)執(zhí)行
這里需要注意的是:這個(gè)共享對(duì)象一定要選好了,這個(gè)共享對(duì)象一定是你需要排隊(duì)執(zhí)行的這些線程對(duì)象所共享的。
//對(duì)象
Object obj=new Object(); //實(shí)例變量(Account對(duì)象是多線程共享的,Account對(duì)象中的實(shí)例變量obj也是共享的)
synchronized(obj){}
括號(hào)里邊只要是共享對(duì)象就行。
Object obj2=new Object(); //局部變量
synchronized(obj2){}
這樣寫(xiě)就不安全了,因?yàn)閛bj2是局部變量,不是共享對(duì)象。
synchronized(“abc”){}
這樣寫(xiě)時(shí)可以的。存在字符串常量池中
寫(xiě)"abc"的話所有線程都會(huì)同步
而如果是寫(xiě)synchronized(this){}的話,我們創(chuàng)建了一個(gè)新的對(duì)象act2可不用共享對(duì)象。
所以最好是寫(xiě)synchronized(this){},比如你要取款,要讓其他取別的賬戶的人也要等嗎?不應(yīng)該,只有同時(shí)對(duì)你這1個(gè)賬戶取款的時(shí)候,需要等待,別人取錢(qián)的時(shí)候,需要從其他賬戶中取錢(qián),就不需要等待。
java中有三大變量的線程安全問(wèn)題
實(shí)例變量,在堆中
靜態(tài)變量,在方法區(qū)
局部變量,在棧中
以上三大變量
局部變量永遠(yuǎn)不會(huì)存在線程安全問(wèn)題
因?yàn)榫植孔兞坎还蚕恚ㄒ粋€(gè)線程一個(gè)棧)
局部變量在棧中,所以局部變量永遠(yuǎn)都不會(huì)共享
實(shí)例變量在堆中,堆只有1個(gè)。
靜態(tài)變量在方法區(qū)中,方法區(qū)只有1個(gè)。
堆和方法區(qū)都是多線程共享的,所以可能存在線程安全問(wèn)題。
局部變量+常量:不會(huì)有線程安全問(wèn)題。
成員變量:可能會(huì)有線程安全問(wèn)題。
同步代碼塊越小,效率越高。
//多線程執(zhí)行這個(gè)方法//synchronized(this)//這里的this是AccountThread對(duì)象,這個(gè)對(duì)象不共享。synchronized(act){ act.withdraw(money); System.out.println(Thread.currentThread().getName()+"賬戶"+act.getActno()+"取款成功,余額:"+act.getBalance());}
在實(shí)例方法上使用synchronized
在實(shí)例方法上可以使用synchronized嗎?可以的。
synchronized出現(xiàn)在實(shí)例方法上,一定鎖的是this
沒(méi)得挑,只能是this,不能是其他的對(duì)象了
所以這種方式不靈活。
另外還有一個(gè)缺點(diǎn):synchronized出現(xiàn)在實(shí)例方法上,表示整個(gè)方法體都需要同步
可能會(huì)擴(kuò)大同步的范圍,導(dǎo)致程序的執(zhí)行效率降低。所以這種方式不常用。
synchronized使用在實(shí)例方法上有什么優(yōu)點(diǎn)?
代碼寫(xiě)的少了,節(jié)儉了。
如果共享的對(duì)象是this,并且需要同步的代碼是整個(gè)方法體,建議使用這種方式。
StringBuffer就是在每個(gè)方法上加了synchronized關(guān)鍵字
使用局部變量的話,最好使用StringBuilder
因?yàn)榫植孔兞坎淮嬖诰€程安全問(wèn)題,選擇StringBuilder,StringBuffer效率比較低。
ArrayList是非線程安全的。
Vector是線程安全的。
HashMap HashSet是非線程安全的。
Hashtable是線程安全的。
總結(jié)
synchronized有三種寫(xiě)法:
??第一種:同步代碼塊
????靈活
??????synchronized(線程共享對(duì)象){
????????同步代碼塊;
??????}
??第二種:在實(shí)例方法上使用synchronized
??????表示共享對(duì)象一定是this
??????并且同步代碼塊是整個(gè)方法體。
??第三種:在靜態(tài)方法上使用synchronized
??????表示找類(lèi)鎖。
??????類(lèi)鎖永遠(yuǎn)只有1把。
??????就算創(chuàng)建了100個(gè)對(duì)象,那類(lèi)鎖也只有一把。
對(duì)象鎖:1個(gè)對(duì)象1把鎖,100個(gè)對(duì)象100把鎖。
類(lèi)鎖:100個(gè)對(duì)象,也可能只是1把類(lèi)鎖。
面試題
//面試題:doother方法的執(zhí)行需不需要等待dosome方法的結(jié)束。
//不需要,因?yàn)閐oother方法沒(méi)有synchronized
public?class?exam01?{ public?static?void?main(String[]?args)?{ MyClass?mc=new?MyClass(); Thread?t1=new?MyThread(mc); Thread?t2=new?MyThread(mc); t1.setName("t1"); t2.setName("t2"); t1.start(); try?{ Thread.sleep(1000); //這個(gè)睡眠的作用是:為了保證t1線程先執(zhí)行 }?catch?(InterruptedException?e)?{ //?TODO?Auto-generated?catch?block e.printStackTrace(); } t2.start(); }}class?MyThread?extends?Thread{ private?MyClass?mc; public?MyThread(MyClass?mc)?{ super(); this.mc?=?mc; } public?void?run(){ if(Thread.currentThread().getName().equals("t1")){ mc.dosome(); } if(Thread.currentThread().getName().equals("t2")){ mc.doOther(); } } }class?MyClass{ public?synchronized?void?dosome(){ System.out.println("doSome?begin"); try?{ Thread.sleep(1000); }?catch?(InterruptedException?e)?{ //?TODO?Auto-generated?catch?block e.printStackTrace(); } System.out.println("doSome?end"); } public?void?doOther(){ System.out.println("doOther?begin"); System.out.println("doOther?end"); }}
當(dāng)在doother上面加了synchronized呢
//面試題:doother方法的執(zhí)行需不需要等待dosome方法的結(jié)束。
//需要,因?yàn)閐oother方法沒(méi)有synchronized
public?synchronized?void?doOther(){ System.out.println("doOther?begin"); System.out.println("doOther?end"); }
//面試題:doother方法的執(zhí)行需不需要等待dosome方法的結(jié)束。
//不用排隊(duì),誰(shuí)也不用管誰(shuí)
MyClass?mc1=new?MyClass();MyClass?mc2=new?MyClass();Thread?t1=new?MyThread(mc1);Thread?t2=new?MyThread(mc2);
//面試題:doother方法的執(zhí)行需不需要等待dosome方法的結(jié)束。
//需要,因?yàn)殪o態(tài)方法是類(lèi)鎖,類(lèi)鎖不管創(chuàng)建了幾個(gè)對(duì)象,類(lèi)鎖只有一把
MyClass?mc1=new?MyClass();MyClass?mc2=new?MyClass();Thread?t1=new?MyThread(mc1);Thread?t2=new?MyThread(mc2);public?synchronized?static?void?dosome(){ System.out.println("doSome?begin"); try?{ Thread.sleep(1000); }?catch?(InterruptedException?e)?{ //?TODO?Auto-generated?catch?block e.printStackTrace(); } System.out.println("doSome?end"); } public?synchronized?static?void?doOther(){ System.out.println("doOther?begin"); System.out.println("doOther?end"); }
這種鎖叫排他鎖:
4.死鎖
synchronized在開(kāi)發(fā)中最好不要嵌套使用,一不小心就可能導(dǎo)致死鎖。
死鎖代碼要會(huì)寫(xiě)。
一般面試官要求你會(huì)寫(xiě)
只有會(huì)寫(xiě)的,才會(huì)在以后的開(kāi)發(fā)中注意這個(gè)事兒
因?yàn)樗梨i很難調(diào)試。
public?class?DeadLock?{ public?static?void?main(String[]?args)?{ Object?o1=new?Object(); Object?o2=new?Object(); //t1線程和t2線程共享o1,o2 Thread?t1=new?MyThread1(o1,o2); Thread?t2=new?MyThread2(o1,o2); t1.start(); t2.start(); }}class?MyThread1?extends?Thread{ Object?o1; Object?o2; public?MyThread1(Object?o1,Object?o2){ this.o1=o1; this.o2=o2; } @Override public?void?run()?{ synchronized?(o1)?{ try?{ Thread.sleep(1000); }?catch?(InterruptedException?e)?{ //?TODO?Auto-generated?catch?block e.printStackTrace(); } synchronized?(o2)?{ } } }}class?MyThread2?extends?Thread{ Object?o1; Object?o2; public?MyThread2(Object?o1,Object?o2){ this.o1=o1; this.o2=o2; } @Override public?void?run()?{ synchronized?(o2)?{ try?{ Thread.sleep(1000); }?catch?(InterruptedException?e)?{ //?TODO?Auto-generated?catch?block e.printStackTrace(); } synchronized?(o1)?{ } } }}
5.開(kāi)發(fā)中應(yīng)該怎么解決線程安全問(wèn)題
聊一聊,我們以后開(kāi)發(fā)中應(yīng)該怎么解決線程安全問(wèn)題?
??是一上來(lái)就選擇線程同步嗎?synchronized
??不是,synchronized會(huì)讓程序的執(zhí)行效率降低,用戶體驗(yàn)不好。
??系統(tǒng)的用戶吞吐量降低。用戶體驗(yàn)差。在不得已的情況下再選擇
??線程同步機(jī)制。
??第一種方案:盡量使用局部變量代替“實(shí)例變量和靜態(tài)變量”。
??第二種方案:如果必須是實(shí)例變量,那么可以考慮創(chuàng)建多個(gè)對(duì)象,這樣實(shí)例變量的內(nèi)存就不共享了。(一個(gè)線程對(duì)應(yīng)1個(gè)對(duì)象,100個(gè)線程對(duì)應(yīng)100個(gè)對(duì)象,對(duì)象不共享,就沒(méi)有數(shù)據(jù)安全問(wèn)題了。)
??第三種方案:如果不能使用局部變量,對(duì)象也不能創(chuàng)建多個(gè),這個(gè)時(shí)候就只能選擇synchronized了。線程同步機(jī)制。
線程這塊還有那些內(nèi)容呢?列舉一下
7.1、守護(hù)線程
7.2、定時(shí)器
7.3、實(shí)現(xiàn)線程的第三種方式:FutureTask方式,實(shí)現(xiàn)Callable接口。(JDK8新特性。)
7.4、關(guān)于Object類(lèi)中的wait和notify方法。(生產(chǎn)者和消費(fèi)者模式?。?/p>
6.守護(hù)線程
守護(hù)線程
java語(yǔ)言中線程分為兩大類(lèi):
??一類(lèi)是:用戶線程
??一類(lèi)是:守護(hù)線程(后臺(tái)線程)
其中具有代表性的就是:垃圾回收線程(守護(hù)線程)。
??守護(hù)線程的特點(diǎn):
??一般守護(hù)線程是一個(gè)死循環(huán),所有的用戶線程只要結(jié)束,
??守護(hù)線程自動(dòng)結(jié)束。
??注意:主線程main方法是一個(gè)用戶線程。
??守護(hù)線程用在什么地方呢?
??每天00:00的時(shí)候系統(tǒng)數(shù)據(jù)自動(dòng)備份。
??這個(gè)需要使用到定時(shí)器,并且我們可以將定時(shí)器設(shè)置為守護(hù)線程。
??一直在那里看著,沒(méi)到00:00的時(shí)候就備份一次。所有的用戶線程如果結(jié)束了,守護(hù)線程自動(dòng)退出,沒(méi)有必要進(jìn)行數(shù)據(jù)備份了。
package?testThread;/* 實(shí)現(xiàn)守護(hù)線程 ?*?*/ public?class?ThreadTest13?{ public?static?void?main(String[]?args)?{ //?TODO?Auto-generated?method?stub Thread?t=new?BakDataThread(); t.setName("備份數(shù)據(jù)的線程"); //啟動(dòng)之前,將線程設(shè)置為守護(hù)線程 t.setDaemon(true); t.start(); //主線程:主線程是用戶線程 for(int?i=0;i"+i); try?{ Thread.sleep(1000); }?catch?(Exception?e)?{ //?TODO:?handle?exception } } }}class?BakDataThread?extends?Thread{ @Override public?void?run()?{ int?i=0; //即使是死循環(huán),但由于該線程是守護(hù)者,當(dāng)用戶線程結(jié)束,守護(hù)線程自動(dòng)終止 while(true){ System.out.println(Thread.currentThread().getName()+"---->"+(++i)); try?{ Thread.sleep(1000); }?catch?(Exception?e)?{ //?TODO:?handle?exception } } }}
7.定時(shí)器
定時(shí)器的作用:
??間隔特定的時(shí)間,執(zhí)行特定的程序。
??每周要進(jìn)行銀行賬戶的總賬操作。
??每天要進(jìn)行數(shù)據(jù)的備份操作。
??在實(shí)際的開(kāi)發(fā)中,每隔多久執(zhí)行一段特定的程序,這種需求是很常見(jiàn)的,
那么在java中其實(shí)可以采用多種方式實(shí)現(xiàn):
??可以使用sleep方法,睡眠,設(shè)置睡眠時(shí)間,沒(méi)到這個(gè)時(shí)間點(diǎn)醒來(lái),執(zhí)行任務(wù)。這種方式是最原始的定時(shí)器。(比較low)
??在java的類(lèi)庫(kù)中已經(jīng)寫(xiě)好了一個(gè)定時(shí)器:java.util.Timer,可以直接拿來(lái)用。不過(guò),這種方式在目前的開(kāi)發(fā)中也很少用,因?yàn)楝F(xiàn)在有很多高級(jí)框架都是支持定時(shí)任務(wù)的。
??在實(shí)際的開(kāi)發(fā)中,目前使用較多的是Spring框架中提供的SpringTask框架,這個(gè)框架只要進(jìn)行簡(jiǎn)單的配置,就可以完成定時(shí)器的任務(wù)。
8.實(shí)現(xiàn)線程的第三種方式:實(shí)現(xiàn)Callable接口
實(shí)現(xiàn)線程的第三種方式:實(shí)現(xiàn)Callable接口。(JDK8新特性。)
這種方式實(shí)現(xiàn)的線程可以獲取線程的返回值。
之前講解的那兩種方式是無(wú)法獲取線程返回值的,因?yàn)閞un方法返回void。
思考:
系統(tǒng)委派一個(gè)線程去執(zhí)行一個(gè)任務(wù),該線程執(zhí)行完任務(wù)之后,可能會(huì)有一個(gè)執(zhí)行結(jié)果,我們?cè)趺茨苣玫竭@個(gè)執(zhí)行結(jié)果呢?
使用第三種方式:實(shí)現(xiàn)Callable接口方式。
public?class?ThreadTest14?{ public?static?void?main(String[]?args)?throws?Exception,?ExecutionException?{ //第一步:創(chuàng)建一個(gè)未來(lái)任務(wù)類(lèi)對(duì)象 //參數(shù)非常重要,需要給一個(gè)callable接口的實(shí)現(xiàn)類(lèi)對(duì)象 FutureTask?task=new?FutureTask(new?Callable(){ @Override //call方法相當(dāng)于是run方法,只不過(guò)這個(gè)有返回值,線程執(zhí)行一個(gè)任務(wù),執(zhí)行之后可能會(huì)有一個(gè)執(zhí)行結(jié)果。 public?Object?call()?throws?Exception?{ System.out.println("call?method?begin"); Thread.sleep(1000); System.out.println("call?method?begin"); int?a=100; int?b=200; return?a+b; //自動(dòng)裝箱 } }); //創(chuàng)建線程對(duì)象 Thread?t=new?Thread(task); //啟動(dòng)線程 t.start(); //這里是main方法,這是在主線程中 //在線程中,怎么獲取t線程的執(zhí)行結(jié)果 //get方法的執(zhí)行會(huì)導(dǎo)致當(dāng)前線程阻塞 Object?obj=task.get(); System.out.println("線程執(zhí)行結(jié)果"+obj); //main方法這里的程序要想執(zhí)行必須等待get()方法的結(jié)束 //而get方法可能需要很久。因?yàn)間et()方法是為了拿另一個(gè)線程的執(zhí)行結(jié)果。 //另一個(gè)線程的執(zhí)行是需要時(shí)間的 System.out.println("hello,world"); }}
這種方式的優(yōu)點(diǎn):可以獲取到線程的執(zhí)行結(jié)果
這種方式的缺點(diǎn):效率比較低,在獲取t線程執(zhí)行結(jié)果的時(shí)候,當(dāng)前線程受阻塞,效率較低。
9.Object類(lèi)中的wait和notify方法
(生產(chǎn)者和消費(fèi)者模式?。?br>??第一:wait和notify方法不是線程對(duì)象的方法,是java中任何一個(gè)java對(duì)象都有的方法,因?yàn)檫@兩個(gè)方式是Object類(lèi)中自帶的。
??wait方法和notify方法不是通過(guò)線程對(duì)象調(diào)用,
??不是這樣的:t.wait(),也不是這樣的:t.notify()…不對(duì)。
??第二:wait()方法作用?
????Object o = new Object();
????o.wait();
??表示:
??讓正在o對(duì)象上活動(dòng)的線程進(jìn)入等待狀態(tài),無(wú)期限等待,直到被喚醒為止。
??o.wait();方法的調(diào)用,會(huì)讓“當(dāng)前線程(正在o對(duì)象上活動(dòng)的線程)”進(jìn)入等待狀態(tài)。
??第三:notify()方法作用?
????Object o = new Object();
????o.notify();
??表示:
??喚醒正在o對(duì)象上等待的線程。
??還有一個(gè)notifyAll()方法:
??這個(gè)方法是喚醒o對(duì)象上處于等待的所有線程。
10.生產(chǎn)者和消費(fèi)者
1.使用wait方法和notify方法實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者模式
2.什么是生產(chǎn)者和消費(fèi)者模式?
生產(chǎn)線程負(fù)責(zé)生產(chǎn),消費(fèi)線程負(fù)責(zé)消費(fèi)
生產(chǎn)線程和消費(fèi)線程要達(dá)到均衡
這是一種特殊的業(yè)務(wù)需求,在這種特殊的情況下需要使用wait方法和notify方法
3.wait和notify方法不是線程對(duì)象的方法,是普通java對(duì)象都有的方法
4.wait方法和notify方法是建立在線程同步的基礎(chǔ)之上。因?yàn)槎嗑€程要同時(shí)操作一個(gè)倉(cāng)庫(kù),有線程安全問(wèn)題
5.wait方法作用:o.wait()讓正在o對(duì)象上活動(dòng)的線程t進(jìn)入等待狀態(tài),并且釋放掉t線程之前占有的o對(duì)象的鎖
6.notify方法的作用:o.notify()讓正在o對(duì)象上等待的線程喚醒,只是5通知,不會(huì)釋放o對(duì)象上之前占有的鎖
7.模擬這樣一個(gè)需求:
倉(cāng)庫(kù)我們采用list集合
list集合中假設(shè)只能存儲(chǔ)1個(gè)元素
1個(gè)元素就表示倉(cāng)庫(kù)滿了
如果list集合中的元素個(gè)數(shù)是0,就表示倉(cāng)庫(kù)空了。
保證list集合中永遠(yuǎn)都是最多存儲(chǔ)1個(gè)元素
必須做到這種效果,生產(chǎn)1個(gè)消費(fèi)1個(gè)。
public?class?ThreadTest15?{ public?static?void?main(String[]?args)?{ //創(chuàng)建一個(gè)倉(cāng)庫(kù)獨(dú)享,共享的 List?list=new?ArrayList(); //創(chuàng)建兩個(gè)線程對(duì)象 //生產(chǎn)者線程 Thread?t1=new?Thread(new?Producer(list)); //消費(fèi)者線程 Thread?t2=new?Thread(new?Consumer(list)); t1.setName("生產(chǎn)者線程"); t2.setName("消費(fèi)者線程"); t1.start(); t2.start(); }}//生產(chǎn)線程class?Producer?implements?Runnable{ //倉(cāng)庫(kù) private?List?list; public?Producer(List?list)?{ this.list?=?list; } public?void?run()?{ //一直生產(chǎn) while(true){ //給倉(cāng)庫(kù)對(duì)象list加鎖 synchronized?(list)?{ if(list.size()>0){ //大于0說(shuō)明倉(cāng)庫(kù)中已經(jīng)有1個(gè)元素了 //當(dāng)前線程進(jìn)入等待狀態(tài),并且釋放list集合的鎖 try?{ list.wait(); }?catch?(InterruptedException?e)?{ //?TODO?Auto-generated?catch?block e.printStackTrace(); } } //程序能夠執(zhí)行到這里說(shuō)明倉(cāng)庫(kù)是空的,可以生產(chǎn) Object?obj?=new?Object(); list.add(obj); System.out.println(Thread.currentThread().getName()+"---->"+obj); //喚醒消費(fèi)者進(jìn)行消費(fèi) list.notifyAll(); } } }}//消費(fèi)線程class?Consumer?implements?Runnable{ //倉(cāng)庫(kù) private?List?list; public?Consumer(List?list)?{ this.list?=?list; } public?void?run()?{ //一直消費(fèi) while(true){ //給倉(cāng)庫(kù)對(duì)象list加鎖 synchronized?(list)?{ if(list.size()==0){ //倉(cāng)里已經(jīng)空了 try?{ //倉(cāng)庫(kù)已經(jīng)空了 //消費(fèi)者線程等待,并釋放掉list集合鎖 list.wait(); }?catch?(InterruptedException?e)?{ //?TODO?Auto-generated?catch?block e.printStackTrace(); } } } Object?obj=list.remove(0); System.out.println(Thread.currentThread().getName()+"---->"+obj); //喚醒生產(chǎn)者生產(chǎn) list.notifyAll(); } }}
相關(guān)學(xué)習(xí)推薦:java基礎(chǔ)
? ??? Java ?? ????? ? ??? ?? ?? ??? ?? ?????. ??? ??? PHP ??? ????? ?? ?? ??? ?????!

? AI ??

Undress AI Tool
??? ???? ??

Undresser.AI Undress
???? ?? ??? ??? ?? AI ?? ?

AI Clothes Remover
???? ?? ???? ??? AI ?????.

Clothoff.io
AI ? ???

Video Face Swap
??? ??? AI ?? ?? ??? ???? ?? ???? ??? ?? ????!

?? ??

??? ??

???++7.3.1
???? ?? ?? ?? ???

SublimeText3 ??? ??
??? ??, ???? ?? ????.

???? 13.0.1 ???
??? PHP ?? ?? ??

???? CS6
??? ? ?? ??

SublimeText3 Mac ??
? ??? ?? ?? ?????(SublimeText3)

JDBC ????? ???? ????? ?? ?? ?? ??? ?? ?? ??? ?? ? ?? ??? ?? ?? ?? ??? ???????. 1. ????? ????? Conn.SetAutoCommit (False)?? ??????. 2. ??? ? ????? ?? ?? SQL ??? ?????. 3. ?? ??? ??? ?? Conn.commit ()?? ???? ??? ???? ???? ?? ??? ???? Conn.Rollback ()?? ??????. ???, ? ??? ???? ????, ??? ???? ????, ?? ??? ??? ?? ??? ??? ???? ? ???????. ?? ?? ?? ???? ????? ??? ???? ?? ?? ???? ???? ??? ????? ?? ??? ??? ? ?? ???? ?? ????.

?? ?? ? ?? ???? ???? ?? Java.Time ???? ???? ??????. 2. LocalDate, LocalDateTime ? LocalTime? ?? ?? ??? ??? ?????. 3. () ???? ???? ?? ??? ??? ????. 4. ???/???? ??? ???? ??? ????? ??? ??????. 5. ZonedDateTime ? Zoneid? ???? ???? ??????. 6. DateTimeFormatter? ?? ?? ? ?? ?? ?? ???; 7. ??? ?? ?? ?? ??? ????? ?? ??????. ?? Java? ?? ??? ???? ??? ??? ???? Java.Timeapi ??? ?? ??? ???????.

Pre-FormancetArtUptimeMoryUsage, Quarkusandmicronautleadduetocompile-timeprocessingandgraalvsupport, withquarkusoftenperforminglightbetterine serverless sinarios.2.thyvelopecosyste,

GO? HTTP ?? ????? ?? ??, ??, ????? IP ? ?? ??? ?? ? ? ????. 1. http.handlerfunc? ???? ????? ????, 2. ??? ???? ?? ?? ??? ?? ??? ??????. ?? ?? ??? ???? ??? ?????? ??? ????? ???? ? ?????. ?? ???? ?? ?? ??, JSON ?? ?? ? ?? ID ??? ?????.

Java 's Garbage Collection (GC)? ???? ???? ???? ??????, ?? ? ??? ??? ? ??? ??? ??? ??? ????. 1.GC? ?? ?? (? : ?? ??, ?? ???, ?? ?? ?)?? ??? ???? ????, ?? ? ??? ??? ???? ?????. 2. ?? ???? ????? ????, ?? ?? ??? ??? ???? ?? ??? ??????. 3. ?? ?? ?? ?? : ??? ?? (Eden, S0, S1)? ?? ????? ?????. ??? ??? ?? ? MajorGC? ???? ? ??? ? ????. Metaspace? ??? ?? ???? ?????. 4. JVM? ??? GC ??? ?????. SerialGC? ??? ?? ????? ?????. ParallelGC? ???? ??????. CMS? ?? ???

??? htmlinput ??? ???? ??? ???? ????? ??? ??? ?? ??? ???? ???? ? ????. 1. ???, ???, ??, ?? ? ??? ?? ??? ??? ?? ?? ?? ??? ???? ???? ??? ? ???? ??? ? ????. 2. HTML5? ?????? ??? ? ?? ?? ??? ?? ? ??? URL, ??, ?? ? ??? ?? ??? ??? ??????. 3. ?? ?? ? ? ??? ??? ???? ?? ??? ???? ???? ?? ???? ?? ???? ???? ?? ? ? ??? ?? ???????.

GradleisBetTerChoiceFormostNewProjectSduetoitssuperiorflexible, Performance, and ModernToolingsupport.1.Gradle'Sgroovy/kotlindslismoreConcisENDEXPRESSIVETHANMAVEN'SVOSEXML.2.GradleOutsMaveninbuildweedweedweedweedweedweedweedweedweedweedweedweedweedweede

DEFER? ??? ???? ?? ??? ??? ???? ? ?????. ?? ??? ?? ? ? ?? ????, ??? ??? ? ?? ?? (LIFO)? ??? ?????. 1. ?? ??? ??? ? ??? ?????. 2. ?? ??? ?? ??? ??? ????? ?????. 3. ?? ? ?? ?? ??? ? ????. 4. ??? ?????? ??? ??? ???? ?????. 5. ?? ??? ???? ?? ??? ?? ??? ?????. ??? ??? ?? ?? ? ???? ???? ? ????.
