生產者消費者問題中的同步機制JAVA設計和實現

問題描述

若干進程經過有限的共享緩衝區交換數據。其中,X個「生產者」進程不斷寫入數據,而Y個「消費者」進程不斷讀出數據;共享緩衝區共有N個;任什麼時候刻只能有一個進程可對公用緩衝池進行操做。ide

問題分析

  咱們已經知道,這樣設計就能夠保證前後順序:對於某一個須要後進行的進程:wait(sth),wait(mutex),signal(mutex),先進行的進程:wait(mutex),signal(mutex),signal(sth)。而本問題也有前後的問題,對於消費者來說,只有先有貨物才能夠消費。對於生產者來說只有有空位才能夠生產。因此須要三個信號量,兩個(full和empty)用來決定前後順序,一個是共享共用緩衝池的標誌。
  對於生產者(Producer):wait(empty),wait(mutex),其餘操做,signal(mutex),signal(full)。
  對於消費者(Consumer):wait(full),wait(mutex),其餘操做,signal(mutex),signal(empty)。


函數

利用記錄型信號量解決

運行環境

Java SE 12ui

實現思路

使用Semaphore類
void acquire(int permits) :獲取指定數目的資源,若是無可用資源將會一直阻塞等待。至關於wait()。
void release(int permits): 釋放指定數目的資源。至關於signal()。設計

代碼實現

final int N=5;//倉庫容量
	private static Integer count = 0;//現有資源數目
	final Semaphore empty = new Semaphore(N);//表示空的數目
    final Semaphore full = new Semaphore(0);//表示滿的數目
    final Semaphore mutex = new Semaphore(1);
	public static void main(String[] args) {
			TestG test=new TestG();
			new Thread(test.new Producer()).start();
			new Thread(test.new Consumer()).start();
			new Thread(test.new Producer()).start();
			new Thread(test.new Consumer()).start();
			new Thread(test.new Producer()).start();
			new Thread(test.new Producer()).start();
			new Thread(test.new Producer()).start();
			new Thread(test.new Consumer()).start();
	}
	class Producer implements Runnable{
		@Override
		public void run() {
		    for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000);//睡眠
                } catch (Exception e) {
                    e.printStackTrace();
                }
                try {
                    empty.acquire(1);//wait(empty)
                    mutex.acquire();//wait(mutex)
                    count++;
                    System.out.println(Thread.currentThread().getName()+ "生產者正在生產,目前總共有" + count);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    mutex.release();//signal(mutex)
                    full.release(1);//signal(full)
                }
            }
		}
	}
	class Consumer implements Runnable{
		@Override
		public void run() {
			for (int i = 0; i < 10; i++) {
				try {
					Thread.sleep(3000);//睡眠
				} catch (Exception e) {
					e.printStackTrace();
				}
				try {
					full.acquire(1);//wait(full)
					mutex.acquire();//wait(mutex)
					count--;
					System.out.println(Thread.currentThread().getName()+ "消費者正在消費,目前還剩" + count);
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					mutex.release();//signal(mutex)
					empty.release(1);//signal(empty)
				}
			}
		}
	}

運行截圖

過程當中出現的問題和注意點

由於Semaphore三個信號量都被聲明爲了final因此一旦被聲明再也不會改變,因此若是經過構造函數傳進來N是不行的,由於在這以前Semaphore已經被聲明而且沒法更改。

code

利用AND信號集解決

運行環境

Java SE 12blog

實現思路

將wait(empty)和wait(mutex)、signal (mutex )和signal (full)、wait (full) 和wait (mutex )、signal (mutex )和signal (empty)結合起來。其實結合起來以後,full和empty就能夠用一個標誌表示了,在這裏我設置爲count表示資源數。用synchronized給mutex加鎖實現同步。進程

代碼實現

private static  Integer count=0;//表示現有貨物資源數目
    
    private static String mutex = "mutex";//標誌資源區(倉庫)是否是被佔用
	public static void main(String[] args) {
		Test test=new Test();
		new Thread(test.new Producer()).start();
		new Thread(test.new Consumer()).start();
		new Thread(test.new Producer()).start();
		new Thread(test.new Consumer()).start();
		new Thread(test.new Producer()).start();
		new Thread(test.new Consumer()).start();
		new Thread(test.new Producer()).start();
		new Thread(test.new Producer()).start();
		new Thread(test.new Producer()).start();
		new Thread(test.new Consumer()).start();
		
	}
	class Producer implements Runnable{

		@Override
		public void run() {
		    for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (mutex) {//同步
                    while (count == 10) {//倉庫滿了
                        try {
                            mutex.wait();//釋放mutex的鎖
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    //生產
                    count++;
                    System.out.println(Thread.currentThread().getName() + "生產者正在生產,貨物共有"+count);
                    mutex.notifyAll();
                }
            }
		}
		
	}
	class Consumer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (mutex) {//同步
                    while (count == 0) {
                        try {
                            mutex.wait();//釋放mutex
                        } catch (Exception e) {
                        }
                    }
                    count--;//消費
                    System.out.println(Thread.currentThread().getName() + "消費者正在消費,貨物還剩"+count);
                    mutex.notifyAll();
                }
            }
        }
}

運行截圖

相關文章
相關標籤/搜索