PV操作的核心就是 PV操作可以同时起到同步与互斥的作用。

1.同步就是通过P操作获取信号量,V操作释放信号量来进行。

2.互斥其实就是,同时操作P操作,结束后进行V操作即可做到。

 

Java上实现PV操作可以通过Semaphore来实现。



package com.multithread.pvoperator;

import java.util.concurrent.Semaphore;

/*
    P(S):
    
    ①将信号量S的值减1,即S=S-1;
    
    ②如果S>=0,则该进程继续执行;否则该进程置为等待状态。
    
    V(S):
    
    ①将信号量S的值加1,即S=S+1;
    
    ②该进程继续执行;如果该信号的等待队列中有等待进程就唤醒一等待进程。
 * 
 * */
public class PVObject {
    
    private Semaphore mSemaphore =null;
    private int Max_size = 0xff;
    private String name = null;
    public PVObject(int size,String name)
    {
        if(size>0)
        {
            Max_size = size;
            mSemaphore = new Semaphore(size);
        }
        this.name = name;
    }
    
    public PVObject(String name)
    {
        Max_size = 1;
        mSemaphore = new Semaphore(1);
        this.name = name;
    }
    
    public void Init(int status)
    {
        if(status<0 || status>Max_size)
        {
            System.out.println("[PVObject][Init]"+name+" wrong,status:"+status);
            return;
        }
        
        if(status == Max_size)
        {
            return;
        }
        
        try {
            mSemaphore.release(Max_size);
            mSemaphore.acquire(Max_size-status);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }    
    }
    
    public void P()
    {
        try {
            //
            mSemaphore.acquire();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }        
    }
    
    public void V()
    {
        mSemaphore.release();        
    }
}



分水果问题Java是实现:



package com.multithread.pvoperator;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class Fruit {
    /*
     * 下面先考虑同步情况即所有“等待”情况:
        第一.爸爸要等待盘子为空。
        第二.儿子要等待盘中水果是桔子。
        第三.女儿要等待盘中水果是苹果。
        接下来来考虑要互斥处理的资源,看起来盘子好像是要作互斥处理的,
        但由于题目中的爸爸、儿子、女儿均只有一个,并且他们访问盘子的条件都不一样,
        所以他们根本不会同时去访问盘子,因此盘子也就不用作互斥处理了
     * 
     * */
    public PVObject mEmptyDash = new PVObject("emptyDash");//1
    public PVObject mApple = new PVObject("apple");    //0
    public PVObject mOranger = new PVObject("oranger");  //0
    public boolean mDadEnd = false;
    public CountDownLatch mLatchDown = new CountDownLatch(3);
    public CountDownLatch mLatchStart = new CountDownLatch(3);
    public Queue<Integer> mQueue = new LinkedList<Integer>();
    public void Start()
    {
        mEmptyDash.Init(1);
        mApple.Init(0);
        mOranger.Init(0);
        mQueue.clear();
        Executor mEcecutor = Executors.newFixedThreadPool(5);
        mEcecutor.execute(new Dad(this));
        mEcecutor.execute(new Daughter(this));
        mEcecutor.execute(new Son(this));

        try {
            mLatchStart.await();
            System.out.println("all thread start");
            
            mLatchDown.await();
            System.out.println("all thread down");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    
    public class Dad extends Thread{
        
        public Fruit mFruit = null;
        boolean flag = true;
        public int MAX_FRUIT_COUNT = 20;
        public int index = 0;
        public Dad(Fruit f)
        {
            mFruit = f;
        }
        @Override
        public void run() {
            mLatchStart.countDown();
            while(flag)
            {
                mFruit.mEmptyDash.P();
                
                index++;
                if(index >=MAX_FRUIT_COUNT)
                {
                    flag = false;
                }
                
                mQueue.offer(index);
                
                if((int)(Math.random()*2) == 1)
                {
                    System.out.println("dad put apple"+index+" to dash");
                    //apply
                    mFruit.mApple.V();
                }
                else
                {
                    //oranger
                    System.out.println("dad put oranger"+index+" to dash");
                    mFruit.mOranger.V();
                }
            }
            mFruit.mDadEnd = true;
            System.out.println("dad thread is end");
            mLatchDown.countDown();
        }
    }
    
    public class Daughter extends Thread{
        
        public Fruit mFruit = null;
        boolean flag = true;
        public Daughter(Fruit f)
        {
            mFruit = f;
        }
        @Override
        public void run() {
            mLatchStart.countDown();
            while(flag)
            {
                mFruit.mOranger.P();
                if(mQueue.size()>0)
                {
                    System.out.println("Daughter get oranger"+mQueue.poll()+" from dash");                
                    mFruit.mEmptyDash.V();
                }
                else
                {
                    System.out.println("Daughter get oranger from dash,but dash is empty");                
                }
                
                if(mFruit.mDadEnd == true)
                {
                    flag = false;
                }
            }
            System.out.println("Daughter thread is end");
            //notify son down,for this dad is down.
            mApple.V();
            mLatchDown.countDown();
        }
    }
    
    public class Son extends Thread{
        
        public Fruit mFruit = null;
        boolean flag = true;
        public Son(Fruit f)
        {
            mFruit = f;
        }
        @Override
        public void run() {
            mLatchStart.countDown();
            while(flag)
            {
                mFruit.mApple.P();
                if(mQueue.size()>0)
                {
                    System.out.println("Son get apple"+mQueue.poll()+" from dash");                
                    mFruit.mEmptyDash.V();
                }
                else
                {
                    System.out.println("Son get apple from dash,but dash is empty");                
                }
                
                if(mFruit.mDadEnd == true)
                {
                    flag = false;
                }
            }
            System.out.println("Son thread is end");
            mOranger.V();
            mLatchDown.countDown();
        }
    }
}



安全岛问题:



package com.multithread.pvoperator;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class SafeIsland {
    
    public PVObject NT = new PVObject("NLoad");
    public PVObject TN = new PVObject("TLoad");
    public PVObject K = new PVObject("K");
    public PVObject L = new PVObject("L");
    public static final int MAX_NANKAI_CAR_COUNT = 2;
    public static final int MAX_TIANJING_CAR_COUNT = 3;
    public CountDownLatch mLatchDown = new CountDownLatch(MAX_NANKAI_CAR_COUNT+MAX_TIANJING_CAR_COUNT);
    
    public class NanKaiCar extends Thread{
        String name = null;
        public NanKaiCar(String name)
        {
            this.name = name;
        }
        @Override
        public void run() {
            System.out.println("[NanKaiCar]"+name+" Thread start");
            try {
                Thread.sleep((long) (Math.random()*100));
                NT.P();
                System.out.println("[NanKaiCar]"+name+" enter crossing N");
                K.P();
                System.out.println("[NanKaiCar]"+name+" walk to M:N->M");
                Thread.sleep((long) (Math.random()*1000));
                System.out.println("[NanKaiCar]"+name+" start walk to T");
                K.V();
                L.P();
                System.out.println("[NanKaiCar]"+name+" walk to T:M->T");
                L.V();
                NT.V();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            mLatchDown.countDown();
            System.out.println("[NanKaiCar]"+name+" walk down");
        }
        
        
    }
    
    public class TianJingCar extends Thread{
        String name = null;
        public TianJingCar(String name)
        {
            this.name = name;
        }
        @Override
        public void run() {
            
            try {
                System.out.println("[TianJingCar]"+name+" Thread start");
                Thread.sleep((long) (Math.random()*100));
                TN.P();
                System.out.println("[TianJingCar]"+name+" enter crossing T");
                L.P();
                System.out.println("[TianJingCar]"+name+" walk to M:T->M");
                Thread.sleep((long) (Math.random()*1000));
                System.out.println("[TianJingCar]"+name+" start walk to N");
                L.V();
                K.P();
                System.out.println("[TianJingCar]"+name+" walk to T:M->N");
                K.V();
                TN.V();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            mLatchDown.countDown();
            System.out.println("[TianJingCar]"+name+" walk down");
        }        
        
    }

    public void start()
    {
        NT.Init(1);
        TN.Init(1);
        K.Init(1);
        L.Init(1);
        Executor mEcecutor = Executors.newFixedThreadPool(MAX_TIANJING_CAR_COUNT+MAX_NANKAI_CAR_COUNT+1);
        for(int i =1;i<=MAX_NANKAI_CAR_COUNT;i++)
        {
            mEcecutor.execute(new NanKaiCar("carN"+i));
        }
        for(int j=1;j<=MAX_TIANJING_CAR_COUNT;j++)
        {
            mEcecutor.execute(new TianJingCar("carT"+j));
        }
        try {
            mLatchDown.await();
            System.out.println("all car has pass road");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}



生产消费者问题伪代码:



package com.multithread.pvoperator;

public class Prosumer {
    //PV 分析 生产者,消费者问题
    /*同步:    生产者:缓冲区有空间,就放入数据  P(EmptyS) 只有空和不空,信号量为1
     *        消费者:缓冲区有数据,就读取数据,并移走数据 P(NotEmptyS),信号量为缓冲区大小
     *互斥:    生产者 写入数据,和消费者移走数据互斥 P(OperatorS),用来互斥,信号量为1
     *        消费者异步读取移动数据,互斥          
     * */
    public class Productor extends Thread{

        @Override
        public void run() {
            while(true)
            {
                P(EmptyS);
                P(OperatorS);
                //operator data
                V(OperatorS);
                V(NotEmptyS);//通知不为空
            }
        }
        
        
    }
    
    public class Consumer extends Thread{

        @Override
        public void run() {
            P(NotEmptyS);
            P(OperatorS);
            //operator data
            V(OperatorS);
            V((EmptyS);
        }        
    }
}

package com.multithread.pvoperator;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class Fruit {
    /*
     * 下面先考虑同步情况即所有“等待”情况:
        第一.爸爸要等待盘子为空。
        第二.儿子要等待盘中水果是桔子。
        第三.女儿要等待盘中水果是苹果。
        接下来来考虑要互斥处理的资源,看起来盘子好像是要作互斥处理的,
        但由于题目中的爸爸、儿子、女儿均只有一个,并且他们访问盘子的条件都不一样,
        所以他们根本不会同时去访问盘子,因此盘子也就不用作互斥处理了
     * 
     * */
    public PVObject mEmptyDash = new PVObject("emptyDash");//1
    public PVObject mApple = new PVObject("apple");    //0
    public PVObject mOranger = new PVObject("oranger");  //0
    public boolean mDadEnd = false;
    public CountDownLatch mLatchDown = new CountDownLatch(3);
    public CountDownLatch mLatchStart = new CountDownLatch(3);
    public Queue<Integer> mQueue = new LinkedList<Integer>();
    public void Start()
    {
        mEmptyDash.Init(1);
        mApple.Init(0);
        mOranger.Init(0);
        mQueue.clear();
        Executor mEcecutor = Executors.newFixedThreadPool(5);
        mEcecutor.execute(new Dad(this));
        mEcecutor.execute(new Daughter(this));
        mEcecutor.execute(new Son(this));

        try {
            mLatchStart.await();
            System.out.println("all thread start");
            
            mLatchDown.await();
            System.out.println("all thread down");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    
    public class Dad extends Thread{
        
        public Fruit mFruit = null;
        boolean flag = true;
        public int MAX_FRUIT_COUNT = 20;
        public int index = 0;
        public Dad(Fruit f)
        {
            mFruit = f;
        }
        @Override
        public void run() {
            mLatchStart.countDown();
            while(flag)
            {
                mFruit.mEmptyDash.P();
                
                index++;
                if(index >=MAX_FRUIT_COUNT)
                {
                    flag = false;
                }
                
                mQueue.offer(index);
                
                if((int)(Math.random()*2) == 1)
                {
                    System.out.println("dad put apple"+index+" to dash");
                    //apply
                    mFruit.mApple.V();
                }
                else
                {
                    //oranger
                    System.out.println("dad put oranger"+index+" to dash");
                    mFruit.mOranger.V();
                }
            }
            mFruit.mDadEnd = true;
            System.out.println("dad thread is end");
            mLatchDown.countDown();
        }
    }
    
    public class Daughter extends Thread{
        
        public Fruit mFruit = null;
        boolean flag = true;
        public Daughter(Fruit f)
        {
            mFruit = f;
        }
        @Override
        public void run() {
            mLatchStart.countDown();
            while(flag)
            {
                mFruit.mOranger.P();
                if(mQueue.size()>0)
                {
                    System.out.println("Daughter get oranger"+mQueue.poll()+" from dash");                
                    mFruit.mEmptyDash.V();
                }
                else
                {
                    System.out.println("Daughter get oranger from dash,but dash is empty");                
                }
                
                if(mFruit.mDadEnd == true)
                {
                    flag = false;
                }
            }
            System.out.println("Daughter thread is end");
            //notify son down,for this dad is down.
            mApple.V();
            mLatchDown.countDown();
        }
    }
    
    public class Son extends Thread{
        
        public Fruit mFruit = null;
        boolean flag = true;
        public Son(Fruit f)
        {
            mFruit = f;
        }
        @Override
        public void run() {
            mLatchStart.countDown();
            while(flag)
            {
                mFruit.mApple.P();
                if(mQueue.size()>0)
                {
                    System.out.println("Son get apple"+mQueue.poll()+" from dash");                
                    mFruit.mEmptyDash.V();
                }
                else
                {
                    System.out.println("Son get apple from dash,but dash is empty");                
                }
                
                if(mFruit.mDadEnd == true)
                {
                    flag = false;
                }
            }
            System.out.println("Son thread is end");
            mOranger.V();
            mLatchDown.countDown();
        }
    }
}