多線程-交替打印字符串的3種寫法

編寫一個可以從 1 到 n 輸出代表這個數(shù)字的字符串的程序料皇,但是:

如果這個數(shù)字可以被 3 整除悠栓,輸出 "fizz"铸磅。
如果這個數(shù)字可以被 5 整除疯特,輸出 "buzz"茬高。
如果這個數(shù)字可以同時被 3 和 5 整除瘩欺,輸出 "fizzbuzz"结胀。
例如辰如,當 n = 15普监,輸出: 1, 2, fizz, 4, buzz, fizz, 7, 8, fizz, buzz, 11, fizz, 13, 14, fizzbuzz。

假設(shè)有這么一個類:

class FizzBuzz {
  public FizzBuzz(int n) { ... }               // constructor
  public void fizz(printFizz) { ... }          // only output "fizz"
  public void buzz(printBuzz) { ... }          // only output "buzz"
  public void fizzbuzz(printFizzBuzz) { ... }  // only output "fizzbuzz"
  public void number(printNumber) { ... }      // only output the numbers
}
請你實現(xiàn)一個有四個線程的多線程版  FizzBuzz琉兜, 同一個 FizzBuzz 實例會被如下四個線程使用:

線程A將調(diào)用 fizz() 來判斷是否能被 3 整除凯正,如果可以,則輸出 fizz豌蟋。
線程B將調(diào)用 buzz() 來判斷是否能被 5 整除廊散,如果可以,則輸出 buzz梧疲。
線程C將調(diào)用 fizzbuzz() 來判斷是否同時能被 3 和 5 整除允睹,如果可以,則輸出 fizzbuzz幌氮。
線程D將調(diào)用 number() 來實現(xiàn)輸出既不能被 3 整除也不能被 5 整除的數(shù)字缭受。

寫法1:使用信號量進行線程間的阻塞

class FizzBuzz {
    private int n;

    private volatile int flag = 1;

    Semaphore s = new Semaphore(1);

    public FizzBuzz(int n) {
        this.n = n;
    }

    // printFizz.run() outputs "fizz".
    public void fizz(Runnable printFizz) throws InterruptedException {
     for(;;) {
         try{
           s.acquire();
           if(flag > n){
              return;
          } 
        if(flag % 3 == 0 && flag % 5 != 0){
           printFizz.run();
           flag++;
         }
         } finally{
            s.release();
         }
            
     }
      
      
    }

    // printBuzz.run() outputs "buzz".
    public void buzz(Runnable printBuzz) throws InterruptedException {
      for(;;) {
          try{
           s.acquire();
          if(flag > n){
            return;
          } 
         if(flag % 5 == 0 && flag % 3 != 0){
           printBuzz.run();
            flag++;
         }
          } finally{
             s.release();
          }   
      }
       
    }

    // printFizzBuzz.run() outputs "fizzbuzz".
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
        for(;;) {
            try{
              s.acquire();
              if(flag > n){
            return;
        } 
        if(flag % 15 == 0){
           printFizzBuzz.run();
            flag++;
         }
            } finally{
              s.release();
            }
       
        }
        
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void number(IntConsumer printNumber) throws InterruptedException {
          for(;;) {
              try{
                      s.acquire(); 
              if(flag > n){
                  return;
              } 
              if( flag % 5 != 0 && flag % 3 != 0){
                    printNumber.accept(flag);
                    flag++;
               }
              } finally{
                  s.release();
              }     
          }
    }
}

寫法2:使用CyclicBarrier 進行線程間的阻塞

class FizzBuzz {
    private int n;

    private static CyclicBarrier barrier = new CyclicBarrier(4);

    public FizzBuzz(int n) {
        this.n = n;
    }

    // printFizz.run() outputs "fizz".
    public void fizz(Runnable printFizz) throws InterruptedException {
        for (int i = 1; i <= n; i++) {
            if (i % 3 == 0 && i % 5 != 0) {
                printFizz.run();
            }
            try {
                barrier.await();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    // printBuzz.run() outputs "buzz".
    public void buzz(Runnable printBuzz) throws InterruptedException {
        for (int i = 1; i <= n; i++) {
            if (i % 3 != 0 && i % 5 == 0) {
                printBuzz.run();
            }
            try {
                barrier.await();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    // printFizzBuzz.run() outputs "fizzbuzz".
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
        for (int i = 1; i <= n; i++) {
            if (i % 3 == 0 && i % 5 == 0) {
                printFizzBuzz.run();
            }
            try {
                barrier.await();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void number(IntConsumer printNumber) throws InterruptedException {
        for (int i = 1; i <= n; i++) {
            if (i % 3 != 0 && i % 5 != 0) {
                printNumber.accept(i);
            }
            try {
                barrier.await();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

寫法3:利用原子類AtomicInteger

class FizzBuzz {
    private int n;
    private AtomicInteger ai = new AtomicInteger(1);

    public FizzBuzz(int n) {
        this.n = n;
    }

    // printFizz.run() outputs "fizz".
    public void fizz(Runnable printFizz) throws InterruptedException {
        while(ai.get() <= n){
            int m = ai.get();
            if(m > n){
                break;
            }
            if(m % 3 == 0 && m % 5 != 0){
                printFizz.run();
                ai.incrementAndGet();
            }
        }
    }

    // printBuzz.run() outputs "buzz".
    public void buzz(Runnable printBuzz) throws InterruptedException {
        while(ai.get() <= n){
            int m = ai.get();
            if(m > n){
                break;
            }
            if(m % 3 != 0 && m % 5 == 0){
                printBuzz.run();
                ai.incrementAndGet();
            }
        }
    }

    // printFizzBuzz.run() outputs "fizzbuzz".
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
       while(ai.get() <= n){
            int m = ai.get();
            if(m > n){
                break;
            }
            if(m % 3 == 0 && m % 5 == 0){
                printFizzBuzz.run();
                ai.incrementAndGet();
            }
        }
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void number(IntConsumer printNumber) throws InterruptedException {
         while(ai.get() <= n){
            int m = ai.get();
            if(m > n){
                break;
            }
            if(m % 3 != 0 && m % 5 != 0){
                printNumber.accept(m);
                ai.incrementAndGet();
            }
        }
    }
}

個人座右銘:主動 行動 思考 反省 總結(jié)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市该互,隨后出現(xiàn)的幾起案子米者,更是在濱河造成了極大的恐慌,老刑警劉巖宇智,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件塘雳,死亡現(xiàn)場離奇詭異陆盘,居然都是意外死亡,警方通過查閱死者的電腦和手機败明,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門隘马,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人妻顶,你說我怎么就攤上這事酸员。” “怎么了讳嘱?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵幔嗦,是天一觀的道長。 經(jīng)常有香客問我沥潭,道長邀泉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任钝鸽,我火速辦了婚禮汇恤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拔恰。我一直安慰自己因谎,他們只是感情好,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布颜懊。 她就那樣靜靜地躺著财岔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪河爹。 梳的紋絲不亂的頭發(fā)上匠璧,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音咸这,去河邊找鬼夷恍。 笑死,一個胖子當著我的面吹牛炊苫,可吹牛的內(nèi)容都是我干的裁厅。 我是一名探鬼主播冰沙,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼侨艾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拓挥?” 一聲冷哼從身側(cè)響起唠梨,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎侥啤,沒想到半個月后当叭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茬故,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年蚁鳖,在試婚紗的時候發(fā)現(xiàn)自己被綠了磺芭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡醉箕,死狀恐怖钾腺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情讥裤,我是刑警寧澤放棒,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站己英,受9級特大地震影響间螟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜损肛,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一厢破、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧荧关,春花似錦溉奕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至同波,卻和暖如春鳄梅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背未檩。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工戴尸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冤狡。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓孙蒙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親悲雳。 傳聞我的和親對象是個殘疾皇子挎峦,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容