摘要:JAVA程序中有多個(gè)線程時(shí),cpu分配給每個(gè)線程的時(shí)間片是在保證均衡的基礎(chǔ)上隨機(jī)分配的,如果這多個(gè)線程有部分相同的功能調(diào)用,那么在功能調(diào)用過程中可能會(huì)因?yàn)闀r(shí)間片的隨機(jī)分配產(chǎn)生預(yù)想不到的結(jié)果。例如火車賣票的程序,火車票是一定的,但賣火車票的窗口到處都有,每個(gè)窗口就相當(dāng)于一個(gè)線程,這么多的線程共用所有的火車票這個(gè)資源。如果在一個(gè)時(shí)間點(diǎn)上,兩個(gè)線程同時(shí)使用這個(gè)資源,那他們?nèi)〕龅幕疖嚻笨赡苁且粯拥模ㄗ惶?hào)
JAVA程序中有多個(gè)線程時(shí),cpu分配給每個(gè)線程的時(shí)間片是在保證均衡的基礎(chǔ)上隨機(jī)分配的,如果這多個(gè)線程有部分相同的功能調(diào)用,那么在功能調(diào)用過程中可能會(huì)因?yàn)闀r(shí)間片的隨機(jī)分配產(chǎn)生預(yù)想不到的結(jié)果。例如火車賣票的程序,火車票是一定的,但賣火車票的窗口到處都有,每個(gè)窗口就相當(dāng)于一個(gè)線程,這么多的線程共用所有的火車票這個(gè)資源。如果在一個(gè)時(shí)間點(diǎn)上,兩個(gè)線程同時(shí)使用這個(gè)資源,那他們?nèi)〕龅幕疖嚻笨赡苁且粯拥模ㄗ惶?hào)一樣),這樣就會(huì)給乘客造成麻煩。
package com.dr.runnable2; class TicketSouce implements Runnable{ //票總數(shù) private int ticket=10; public void run() { for(int i=1;i<50;i++) { if(ticket>0){ System.out.println(Thread.currentThread().getName()+"號(hào)窗口賣出"+this.ticket--+"號(hào)票"); } } } } public class Test { public static void main(String args[]) { TicketSouce mt=new TicketSouce(); //基于火車票創(chuàng)建三個(gè)窗口 new Thread(mt,"a").start(); new Thread(mt,"b").start(); new Thread(mt,"c").start(); } }
可能的運(yùn)行結(jié)果如下 (小概率)
出現(xiàn)相同的10號(hào)票是因?yàn)楫?dāng)a線程執(zhí)行“ System.out.println(Thread.currentThread().getName()+"號(hào)窗口賣出"+this.ticket--+"號(hào)票")”時(shí)還沒有對(duì)ticket進(jìn)行自減1,時(shí)間片就被分配到b線程,結(jié)果b線程也取到了10號(hào)票。出現(xiàn)0和-1是因?yàn)閎線程取出1號(hào)票還沒有對(duì)ticket進(jìn)行自減1,a和c線程就相繼取得時(shí)間片利用ticket=1成功通過if(ticket>0)的判斷句進(jìn)入循環(huán),然后再回到b將ticket減為0,結(jié)果先執(zhí)行的a輸出0,后執(zhí)行的c輸出-1。
synchronized線程同步, 用于解決此類問題。同步方法synchronized void method(){}或同步語句synchronized(object){}放置在正確的位置均可實(shí)現(xiàn)。使用后當(dāng)某線程進(jìn)行功能調(diào)用時(shí)在沒有得到結(jié)果之前不會(huì)返回,其他線程也無法調(diào)用,如果需要調(diào)用會(huì)暫時(shí)阻塞。將程序改為同步方法:
package com.dr.runnable2; class TicketSouce implements Runnable{ //票總數(shù) private int ticket=10; public void run() { for(int i=1;i<50;i++) { this.sale(); } } public synchronized void sale(){ if(ticket>0){ System.out.println(Thread.currentThread().getName()+"號(hào)窗口賣出"+this.ticket--+"號(hào)票"); } } } public class Test { public static void main(String args[]) { TicketSouce mt=new TicketSouce(); //基于火車票創(chuàng)建三個(gè)窗口 new Thread(mt,"a").start(); new Thread(mt,"b").start(); new Thread(mt,"c").start(); } }
或同步語句:
package com.dr.runnable2; class TicketSouce implements Runnable{ //票總數(shù) private int ticket=10; public void run() { for(int i=1;i<50;i++) { synchronized(this){ if(ticket>0){ System.out.println(Thread.currentThread().getName()+"號(hào)窗口賣出"+this.ticket--+"號(hào)票"); } } } } } public class Test { public static void main(String args[]) { TicketSouce mt=new TicketSouce(); //基于火車票創(chuàng)建三個(gè)窗口 new Thread(mt,"a").start(); new Thread(mt,"b").start(); new Thread(mt,"c").start(); } }
運(yùn)行結(jié)果: