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

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

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

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

  1. package com.multithread.pvoperator;
  2.  
  3. import java.util.concurrent.Semaphore;
  4.  
  5. /*
  6. P(S):
  7.  
  8. ①将信号量S的值减1,即S=S-1;
  9.  
  10. ②如果S>=0,则该进程继续执行;否则该进程置为等待状态。
  11.  
  12. V(S):
  13.  
  14. ①将信号量S的值加1,即S=S+1;
  15.  
  16. ②该进程继续执行;如果该信号的等待队列中有等待进程就唤醒一等待进程。
  17. *
  18. * */
  19. public class PVObject {
  20.  
  21. private Semaphore mSemaphore =null;
  22. private int Max_size = 0xff;
  23. private String name = null;
  24. public PVObject(int size,String name)
  25. {
  26. if(size>0)
  27. {
  28. Max_size = size;
  29. mSemaphore = new Semaphore(size);
  30. }
  31. this.name = name;
  32. }
  33.  
  34. public PVObject(String name)
  35. {
  36. Max_size = 1;
  37. mSemaphore = new Semaphore(1);
  38. this.name = name;
  39. }
  40.  
  41. public void Init(int status)
  42. {
  43. if(status<0 || status>Max_size)
  44. {
  45. System.out.println("[PVObject][Init]"+name+" wrong,status:"+status);
  46. return;
  47. }
  48.  
  49. if(status == Max_size)
  50. {
  51. return;
  52. }
  53.  
  54. try {
  55. mSemaphore.release(Max_size);
  56. mSemaphore.acquire(Max_size-status);
  57. } catch (InterruptedException e) {
  58. // TODO Auto-generated catch block
  59. e.printStackTrace();
  60. }
  61. }
  62.  
  63. public void P()
  64. {
  65. try {
  66. //
  67. mSemaphore.acquire();
  68. } catch (InterruptedException e) {
  69. // TODO Auto-generated catch block
  70. e.printStackTrace();
  71. }
  72. }
  73.  
  74. public void V()
  75. {
  76. mSemaphore.release();
  77. }
  78. }

分水果问题Java是实现:

  1. package com.multithread.pvoperator;
  2.  
  3. import java.util.LinkedList;
  4. import java.util.Queue;
  5. import java.util.concurrent.CountDownLatch;
  6. import java.util.concurrent.Executor;
  7. import java.util.concurrent.Executors;
  8.  
  9. public class Fruit {
  10. /*
  11. * 下面先考虑同步情况即所有“等待”情况:
  12. 第一.爸爸要等待盘子为空。
  13. 第二.儿子要等待盘中水果是桔子。
  14. 第三.女儿要等待盘中水果是苹果。
  15. 接下来来考虑要互斥处理的资源,看起来盘子好像是要作互斥处理的,
  16. 但由于题目中的爸爸、儿子、女儿均只有一个,并且他们访问盘子的条件都不一样,
  17. 所以他们根本不会同时去访问盘子,因此盘子也就不用作互斥处理了
  18. *
  19. * */
  20. public PVObject mEmptyDash = new PVObject("emptyDash");//
  21. public PVObject mApple = new PVObject("apple"); //
  22. public PVObject mOranger = new PVObject("oranger"); //
  23. public boolean mDadEnd = false;
  24. public CountDownLatch mLatchDown = new CountDownLatch(3);
  25. public CountDownLatch mLatchStart = new CountDownLatch(3);
  26. public Queue<Integer> mQueue = new LinkedList<Integer>();
  27. public void Start()
  28. {
  29. mEmptyDash.Init(1);
  30. mApple.Init(0);
  31. mOranger.Init(0);
  32. mQueue.clear();
  33. Executor mEcecutor = Executors.newFixedThreadPool(5);
  34. mEcecutor.execute(new Dad(this));
  35. mEcecutor.execute(new Daughter(this));
  36. mEcecutor.execute(new Son(this));
  37.  
  38. try {
  39. mLatchStart.await();
  40. System.out.println("all thread start");
  41.  
  42. mLatchDown.await();
  43. System.out.println("all thread down");
  44. } catch (InterruptedException e) {
  45. // TODO Auto-generated catch block
  46. e.printStackTrace();
  47. }
  48. }
  49.  
  50. public class Dad extends Thread{
  51.  
  52. public Fruit mFruit = null;
  53. boolean flag = true;
  54. public int MAX_FRUIT_COUNT = 20;
  55. public int index = 0;
  56. public Dad(Fruit f)
  57. {
  58. mFruit = f;
  59. }
  60. @Override
  61. public void run() {
  62. mLatchStart.countDown();
  63. while(flag)
  64. {
  65. mFruit.mEmptyDash.P();
  66.  
  67. index++;
  68. if(index >=MAX_FRUIT_COUNT)
  69. {
  70. flag = false;
  71. }
  72.  
  73. mQueue.offer(index);
  74.  
  75. if((int)(Math.random()*2) == 1)
  76. {
  77. System.out.println("dad put apple"+index+" to dash");
  78. //apply
  79. mFruit.mApple.V();
  80. }
  81. else
  82. {
  83. //oranger
  84. System.out.println("dad put oranger"+index+" to dash");
  85. mFruit.mOranger.V();
  86. }
  87. }
  88. mFruit.mDadEnd = true;
  89. System.out.println("dad thread is end");
  90. mLatchDown.countDown();
  91. }
  92. }
  93.  
  94. public class Daughter extends Thread{
  95.  
  96. public Fruit mFruit = null;
  97. boolean flag = true;
  98. public Daughter(Fruit f)
  99. {
  100. mFruit = f;
  101. }
  102. @Override
  103. public void run() {
  104. mLatchStart.countDown();
  105. while(flag)
  106. {
  107. mFruit.mOranger.P();
  108. if(mQueue.size()>0)
  109. {
  110. System.out.println("Daughter get oranger"+mQueue.poll()+" from dash");
  111. mFruit.mEmptyDash.V();
  112. }
  113. else
  114. {
  115. System.out.println("Daughter get oranger from dash,but dash is empty");
  116. }
  117.  
  118. if(mFruit.mDadEnd == true)
  119. {
  120. flag = false;
  121. }
  122. }
  123. System.out.println("Daughter thread is end");
  124. //notify son down,for this dad is down.
  125. mApple.V();
  126. mLatchDown.countDown();
  127. }
  128. }
  129.  
  130. public class Son extends Thread{
  131.  
  132. public Fruit mFruit = null;
  133. boolean flag = true;
  134. public Son(Fruit f)
  135. {
  136. mFruit = f;
  137. }
  138. @Override
  139. public void run() {
  140. mLatchStart.countDown();
  141. while(flag)
  142. {
  143. mFruit.mApple.P();
  144. if(mQueue.size()>0)
  145. {
  146. System.out.println("Son get apple"+mQueue.poll()+" from dash");
  147. mFruit.mEmptyDash.V();
  148. }
  149. else
  150. {
  151. System.out.println("Son get apple from dash,but dash is empty");
  152. }
  153.  
  154. if(mFruit.mDadEnd == true)
  155. {
  156. flag = false;
  157. }
  158. }
  159. System.out.println("Son thread is end");
  160. mOranger.V();
  161. mLatchDown.countDown();
  162. }
  163. }
  164. }

安全岛问题:

  1. package com.multithread.pvoperator;
  2.  
  3. import java.util.concurrent.CountDownLatch;
  4. import java.util.concurrent.Executor;
  5. import java.util.concurrent.Executors;
  6.  
  7. public class SafeIsland {
  8.  
  9. public PVObject NT = new PVObject("NLoad");
  10. public PVObject TN = new PVObject("TLoad");
  11. public PVObject K = new PVObject("K");
  12. public PVObject L = new PVObject("L");
  13. public static final int MAX_NANKAI_CAR_COUNT = 2;
  14. public static final int MAX_TIANJING_CAR_COUNT = 3;
  15. public CountDownLatch mLatchDown = new CountDownLatch(MAX_NANKAI_CAR_COUNT+MAX_TIANJING_CAR_COUNT);
  16.  
  17. public class NanKaiCar extends Thread{
  18. String name = null;
  19. public NanKaiCar(String name)
  20. {
  21. this.name = name;
  22. }
  23. @Override
  24. public void run() {
  25. System.out.println("[NanKaiCar]"+name+" Thread start");
  26. try {
  27. Thread.sleep((long) (Math.random()*100));
  28. NT.P();
  29. System.out.println("[NanKaiCar]"+name+" enter crossing N");
  30. K.P();
  31. System.out.println("[NanKaiCar]"+name+" walk to M:N->M");
  32. Thread.sleep((long) (Math.random()*1000));
  33. System.out.println("[NanKaiCar]"+name+" start walk to T");
  34. K.V();
  35. L.P();
  36. System.out.println("[NanKaiCar]"+name+" walk to T:M->T");
  37. L.V();
  38. NT.V();
  39. } catch (InterruptedException e) {
  40. // TODO Auto-generated catch block
  41. e.printStackTrace();
  42. }
  43. mLatchDown.countDown();
  44. System.out.println("[NanKaiCar]"+name+" walk down");
  45. }
  46.  
  47. }
  48.  
  49. public class TianJingCar extends Thread{
  50. String name = null;
  51. public TianJingCar(String name)
  52. {
  53. this.name = name;
  54. }
  55. @Override
  56. public void run() {
  57.  
  58. try {
  59. System.out.println("[TianJingCar]"+name+" Thread start");
  60. Thread.sleep((long) (Math.random()*100));
  61. TN.P();
  62. System.out.println("[TianJingCar]"+name+" enter crossing T");
  63. L.P();
  64. System.out.println("[TianJingCar]"+name+" walk to M:T->M");
  65. Thread.sleep((long) (Math.random()*1000));
  66. System.out.println("[TianJingCar]"+name+" start walk to N");
  67. L.V();
  68. K.P();
  69. System.out.println("[TianJingCar]"+name+" walk to T:M->N");
  70. K.V();
  71. TN.V();
  72. } catch (InterruptedException e) {
  73. // TODO Auto-generated catch block
  74. e.printStackTrace();
  75. }
  76. mLatchDown.countDown();
  77. System.out.println("[TianJingCar]"+name+" walk down");
  78. }
  79.  
  80. }
  81.  
  82. public void start()
  83. {
  84. NT.Init(1);
  85. TN.Init(1);
  86. K.Init(1);
  87. L.Init(1);
  88. Executor mEcecutor = Executors.newFixedThreadPool(MAX_TIANJING_CAR_COUNT+MAX_NANKAI_CAR_COUNT+1);
  89. for(int i =1;i<=MAX_NANKAI_CAR_COUNT;i++)
  90. {
  91. mEcecutor.execute(new NanKaiCar("carN"+i));
  92. }
  93. for(int j=1;j<=MAX_TIANJING_CAR_COUNT;j++)
  94. {
  95. mEcecutor.execute(new TianJingCar("carT"+j));
  96. }
  97. try {
  98. mLatchDown.await();
  99. System.out.println("all car has pass road");
  100. } catch (InterruptedException e) {
  101. // TODO Auto-generated catch block
  102. e.printStackTrace();
  103. }
  104. }
  105.  
  106. }

生产消费者问题伪代码:

  1. package com.multithread.pvoperator;
  2.  
  3. public class Prosumer {
  4. //PV 分析 生产者,消费者问题
  5. /*同步: 生产者:缓冲区有空间,就放入数据 P(EmptyS) 只有空和不空,信号量为1
  6. * 消费者:缓冲区有数据,就读取数据,并移走数据 P(NotEmptyS),信号量为缓冲区大小
  7. *互斥: 生产者 写入数据,和消费者移走数据互斥 P(OperatorS),用来互斥,信号量为1
  8. * 消费者异步读取移动数据,互斥
  9. * */
  10. public class Productor extends Thread{
  11.  
  12. @Override
  13. public void run() {
  14. while(true)
  15. {
  16. P(EmptyS);
  17. P(OperatorS);
  18. //operator data
  19. V(OperatorS);
  20. V(NotEmptyS);//通知不为空
  21. }
  22. }
  23.  
  24. }
  25.  
  26. public class Consumer extends Thread{
  27.  
  28. @Override
  29. public void run() {
  30. P(NotEmptyS);
  31. P(OperatorS);
  32. //operator data
  33. V(OperatorS);
  34. V((EmptyS);
  35. }
  36. }
  37. }

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操作上 (续)的更多相关文章

  1. 多线程同步内功心法——PV操作上(未完待续。。。)

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...

  2. 多线程面试题系列(12):多线程同步内功心法——PV操作上

    上面的文章讲解了在Windows系统下实现多线程同步互斥的方法,为了提高在实际问题中分析和思考多个线程之间同步互斥问题的能力,接下来将讲解PV操作,这也是操作系统中的重点和难点.本文将会先简要介绍下P ...

  3. C++第五十二篇 -- 多线程之消息传递

    主线程向子线程发送消息 参考链接:https://www.cnblogs.com/ranjiewen/p/5729539.html 1. 创建线程语句 HANDLE hThread; DWORD dw ...

  4. “全栈2019”Java多线程第二十二章:饥饿线程(Starvation)详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  5. “全栈2019”Java多线程第十二章:后台线程setDaemon()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  6. “全栈2019”Java多线程第十六章:同步synchronized关键字详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  7. 解剖SQLSERVER 第十二篇 OrcaMDF 行压缩支持(译)

    解剖SQLSERVER 第十二篇   OrcaMDF 行压缩支持(译) http://improve.dk/orcamdf-row-compression-support/ 在这两个月的断断续续的开发 ...

  8. 第十二篇 SQL Server代理多服务器管理

    本篇文章是SQL Server代理系列的第十二篇,详细内容请参考原文 在这一系列的上一篇,我们查看了维护计划,一个维护计划可能会创建多个作业,多个计划.你还简单地看了SSIS子系统,并查看了维护计划作 ...

  9. 第十二篇 Integration Services:高级日志记录

    本篇文章是Integration Services系列的第十二篇,详细内容请参考原文. 简介在前一篇文章我们配置了SSIS内置日志记录,演示了简单和高级日志配置,保存并查看日志配置,生成自定义日志消息 ...

随机推荐

  1. 20155332 2006-2007-2 《Java程序设计》第2周学习总结

    20155332 2006-2007-2 <Java程序设计>第2周学习总结 教材学习内容总结 在JAVA中分为基本类型和类类型两大类型系统. JAVA中的基本类型主要分为如下几类: 1. ...

  2. QTC++监控USB插拔

    #if defined(Q_OS_WIN) #include <qt_windows.h> #include <QtCore/qglobal.h> #include <d ...

  3. TMDXEVM6678L EVM开发板初使用(1)

    1. 板子上电风扇转个不停,震动很大. 2. 有点懵逼,第一步干啥,首先安装板子的软件开发包,资料下载地址http://www2.advantech.com/Support/TI-EVM/6678le ...

  4. 【JUC源码解析】LinkedBlockingQueue

    简介 一个基于链表的阻塞队列,FIFO的顺序,head指向的元素等待时间最长,tail指向的元素等待时间最短,新元素从队列尾部添加,检索元素从队列头部开始,队列的容量,默认是Integer#MAX_V ...

  5. 人脸检测及识别python实现系列(5)——利用keras库训练人脸识别模型

    人脸检测及识别python实现系列(5)——利用keras库训练人脸识别模型 经过前面稍显罗嗦的准备工作,现在,我们终于可以尝试训练我们自己的卷积神经网络模型了.CNN擅长图像处理,keras库的te ...

  6. PHASER3 设置场景SCENE SLEEPING休眠和WAKE唤醒

    A good way to set scene stop when hidden and run while visible again ! 使用sleep和wake方法的好处: 1.可以彻底让sce ...

  7. 【转】AOE机制的DSL及其实际运用

    AOE这个词的意思,我相信玩过WOW的人都不陌生,包括玩过LoL的也不会陌生,说穿了就是一个区域内发生效果(Area of effect).这里我们要讨论的就是关于一个适合于几乎所有游戏的AOE机制, ...

  8. mac 的一些使用技巧

    1. mac有一个自带的服务器环境, 目录路径 /Library/WebServer/Documents 打开终端  a. 启动 sudo apachectl start b. 重新启动 sudo a ...

  9. ES6的新特性(21)——Proxy

    Proxy 概述 Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程. Proxy 可以理解成,在目标对 ...

  10. wireshark解析https协议方法

    本文仅介绍通过协商密钥的方式实现https解析的方法 wireshark支持pem