六、Java高級特性(線程之間的通信)

1、等待和通知機制(wait、notify)

wait()方法

使當前執行代碼的線程進入等待的狀態,該方法是Object類的方法,使當前線程進入預執行隊列,使用wait()方法前,必須拿到對象級別的鎖,即只能在同步方法裏執行,執行wait方法之後會釋放鎖,線程進入了等待的狀態。

notify方法

和wait方法一樣,同樣要拿到對象級別的鎖,也就是隻能在同步方法內執行。notify的作用是通知調用wait方法進入等待的線程,恢復執行。調用notify方法之後,不會立即釋放鎖,程wait狀態的線程也不會立即拿到鎖,只有調用notify方法的線程執行完同步方法之後,纔會釋放鎖。釋放鎖完之後,當執行wait方法的線程拿到鎖之後,就會恢復執行。

notifyAll方法

如果有多個線程調用了wait方法,只調用notify通知,則是隨機通知某一個線程恢復執行,如果想要通知全部線程,則調用notifyAll方法

wait和sleep的區別

相同點:wait和sleep都會使當前線程暫停執行
不同點:
1、wait是Object類的方法,而sleep是Thread的方法
2、wait的執行必須要拿到對象級別的鎖,也就是必須在同步方法裏執行,而sleep不是必須的。
3、wait執行完之後,會立即釋放鎖,使得當前線程暫停執行。而sleep方法雖然是使得當前線程暫停執行,不會釋放鎖,也就是說當sleep執行在同步方法裏的時候,會使得當前線程進入阻塞的狀態。

2、生產者和消費者模式(實現線程之間的通信)

生產者

package com.company;

import java.util.Date;

/**
 * 生產者
 */
public class ProductThread extends Thread {
    private Goods goods;

    public ProductThread(Goods goods) {
        this.goods = goods;
    }

    @Override
    public void run() {
        super.run();
        while (true) {
            productGoods();
        }
    }

    /**
     * 生產商品
     */
    private void productGoods() {
        synchronized (goods) {
            try {
                //如果商品還沒被消費,則先等被消費
                if (goods.getName() != null) {
                    goods.wait();
                }
                //如果已經被消費了,則生產商品
                goods.setName(new Date().getTime() + "");
                System.out.println("生產商品:" + goods.getName());
                //通知消費
                goods.notify();
                Thread.sleep(1000);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }


        }

    }
}

消費者

package com.company;

/**
* 消費者
*/
public class ConsumerThread extends Thread {
   //消費商品
   private Goods goods;

   public ConsumerThread(Goods goods) {
       this.goods = goods;
   }

   @Override
   public void run() {
       super.run();
       while (true) {
           cosumerGoods();
       }
   }

   /**
    * 消費商品
    */
   private void cosumerGoods() {
       synchronized (goods) {
           try {
               //如果商品還沒被生產,則先等生產
               if (goods.getName() == null) {
                   goods.wait();
               }
               System.out.println("消費商品:" + goods.getName());
               //如果商品已經生產了,直接消費商品
               goods.setName(null);
               //通知生產
               goods.notify();
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }


       }

   }
}

商品

package com.company;

/**
 * 商品類
 */
public class Goods {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

測試

package com.company;

public class MyMain {

    public static void main(String[] args) {
        Goods goods = new Goods();
        ProductThread productThread = new ProductThread(goods);
        ConsumerThread consumerThread = new ConsumerThread(goods);
        productThread.start();
        consumerThread.start();

    }
}

結果

生產商品:1607925851349
消費商品:1607925851349
生產商品:1607925853350
消費商品:1607925853350
生產商品:1607925855351
消費商品:1607925855351
生產商品:1607925857351
消費商品:1607925857351

生產者消費者模型分析

  • 生產者生產商品,當發現商品還沒有被消費的時候,則進入等待狀態。如果商品已經被消費沒有了,則生產商品,通知消費者消費。
  • 消費者消費商品,當發現商品還沒有被生產的時候,則進入等待狀態。如果商品已經被生產了,則消費商品,通知生產者繼續生產商品。
  • 生產者和消費者都需要對商品進行加鎖,防止線程安全問題。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章