• 转---秒杀多线程第十二篇 多线程同步内功心法——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();
            }
        }
    }

  • 相关阅读:
    sqlserver调优-索引
    浮点数的这些坑,你未必知道-深入理解浮点数的规律
    生产环境部署springcloud微服务启动慢的问题排查
    redis传输协议规范-下(Redis Protocol specification)
    一步步完成“迷你版” 的ASP.NET Core框架
    安全漏洞整改系列(一)
    docker实战(二)之redis的使用
    docker实战(一)之Tomcat的安装
    docker安装步骤
    WPF后台操作前台元素之查找对象
  • 原文地址:https://www.cnblogs.com/deman/p/4110160.html
Copyright © 2020-2023  润新知