首页 > 代码库 > 转---秒杀多线程第十二篇 多线程同步内功心法——PV操作上 (续)

转---秒杀多线程第十二篇 多线程同步内功心法——PV操作上 (续)

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();
        }
    }
}

转---秒杀多线程第十二篇 多线程同步内功心法——PV操作上 (续)