用Java實現PV操作——父親女兒喫水果問題

在學習操作系統的進程的同步操作中,老師有道實驗題,要求使用信號量完成父親女兒喫水果問題。基於C系語言對我的不友好,我詢問了老師能否使用Java實現(因爲Java裏邊好多方法都是現成的,不用自己寫~~),距離學習Java線程已經過了快一年,剛好複習複習。

【問題描述】桌上有一空盤,最多允許存放一個水果。爸爸可向盤中放一個蘋果或放一個桔子,兒子專等喫盤中的桔子,女兒專等喫蘋果。 試用P、V操作實現爸爸、兒子、女兒三個併發進程的同步。 提示:設置一個信號量表示可否向盤中放水果,一個信號量表示可否取桔子,一個信號量表示可否取蘋果。

問題分析

  • 桌子上只有一個盤子,父親每次只能放入一種水果,同一時間內,盤子裏只能有一種水果
  • 兒子和女兒從盤子裏拿水果,水果只有一個,同一時間內只有一個人喫水果,所以兒子和女兒也是互斥關係
  • 父親放何種水果制約了女兒和兒子取何種水果

Java中的Semaphore

//此信號量獲得一個許可,在提供一個許可前將線程堵塞,否則線程被中斷。獲得一個許可並立即返回,將許可數減一
  public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
//釋放一個許可,將其返回給信號量。將可用的許可數加一
 public void release() {
        sync.releaseShared(1);
    }

也就是說,在初始化一個信號量的時候,例如構造函數: Semaphore Semaphore = new Semaphore(1); 信號量的許可數爲1,每acquire一次,許可數就 -1,每release一次,許可數就+1,當許可數變爲0還acquire的話,該線程會進入阻塞狀態,直到release方法將許可數置爲1,才能執行

實例代碼

package thread;

import java.util.concurrent.Semaphore;

/**
 * @ClassName App
 * @Author hobo
 * @Date 19-4-17 下午3:37
 * @Description
 **/
public class App {

    //初始化桌子爲空的信號量爲1 使父親線程能夠運行  1 桌子爲空,0 桌子不爲空
    public static Semaphore diskEmpty = new Semaphore(1);

    //初始化信號量爲0,使得女兒和兒子的進程阻塞
    public static Semaphore haveOrange = new Semaphore(0);

    public static Semaphore haveApple = new Semaphore(0);

    public static void main(String[] args) {
        Father father = new Father();
        Son son = new Son();
        Daughter daughter = new Daughter();

        father.start();
        son.start();
        daughter.start();
    }

}

父親線程

package thread;

import java.util.Random;

/**
 * @ClassName Father
 * @Author hobo
 * @Date 19-4-17 下午3:36
 * @Description
 **/
public class Father extends Thread {

    @Override
    public void run() {
        try {
            while (true) {
                //使用隨機數控制父親放入橘子還是蘋果
                Random random = new Random();
                int n = random.nextInt(100);

                App.diskEmpty.acquire();
                if (n % 2 == 0) {
                    Disk.putFruit("橘子");
                    App.haveOrange.release();
                } else {
                    Disk.putFruit("蘋果");
                    App.haveApple.release();
                }
                sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

兒子線程

package thread;

/**
 * @ClassName Son
 * @Author hobo
 * @Date 19-4-17 下午3:36
 * @Description
 **/
public class Son extends Thread {

    private static String name = "兒子";

    @Override
    public void run() {

        try {
            while (true) {
                App.haveOrange.acquire();
                Disk.getFruit(name);

                sleep(1000);

                App.diskEmpty.release();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

女兒線程

package thread;

/**
 * @ClassName Daughter
 * @Author hobo
 * @Date 19-4-17 下午3:37
 * @Description
 **/
public class Daughter extends Thread {

    private static String name = "女兒";

    @Override
    public void run() {
        try {
            while (true) {
                App.haveApple.acquire();
                Disk.getFruit(name);
                sleep(1000);
                App.diskEmpty.release();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

盤子

package thread;

/**
 * @ClassName Disk
 * @Author hobo
 * @Date 19-4-17 下午3:37
 * @Description
 **/
public class Disk {

    private static String fruitName = "";

    public static void putFruit(String fruit) {
        fruitName = fruit;
        System.out.println("父親往盤子裏邊放了一個" + fruit);
    }

    public static String getFruit(String name) {
        System.out.println(name + "吃了一個" + fruitName);
        return fruitName;
    }
}

運行結果
在這裏插入圖片描述
Github傳送門

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章