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");//
public PVObject mApple = new PVObject("apple"); //
public PVObject mOranger = new PVObject("oranger"); //
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操作上 (续)的更多相关文章

  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. 20155333 2016-2017-2 《Java程序设计》第4周学习总结

    20155333 2016-2017-2 <Java程序设计>第4周学习总结 教材学习内容总结 继承基本上就是避免多个类间重复定义的共同行为,在Java中,子类只能继承一个父类. priv ...

  2. 20145226夏艺华 《Java程序设计》第10周学习总结

    教材学习内容总结 学习目标 了解计算机网络基础 掌握Java Socket编程 网络编程 网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据.程序员所作的事情就是把数据发送到指定的位置,或者 ...

  3. WPF设置ListBoxItem失去焦点时的背景色

    <!--全局ListBoxItem--> <Style TargetType="ListBoxItem"> <Style.Resources> ...

  4. 【MYSQL权限】数据库权限部署

    背景:没有划分数据库权限,所有人共用一个账号 本人公司现有的数据库账号分布情况: 所有人用一个账号(包括程序里面访问数据库的的配置文件里面的账号),该账号除删库权限,其他权限大部分都有. 这样非数据库 ...

  5. Electron小记

    一.安装 1.安装NodeJS 2.安装electronjs:npm install -g electron --unsafe-perm=true --allow-root 安装完,环境为: Node ...

  6. 那些年安装Appium遇到的坑

      安装appium以及相关的总体记录   1 主要流程是参照这个来 https://www.cnblogs.com/wangyinghao/p/5780151.html 细节参考虫师的博客 http ...

  7. Jupyter 安装并配置工作路径[转]

    1.通过python的pip方式安装jupyterpython和pip都安装好后,通过cmd进入命令提示窗口,找到python安装目录下的Script目录,例如我的是路径是:C:\Program Fi ...

  8. 《More Effective C++》读书笔记(零)Basic 基础条款

    这是篇读书笔记,只记录自己的理解和总结,一般情况不对其举例子具体说明,因为那正是书本身做的事情,我的笔记作为梳理和复习之用,划重点.我推荐学C++的人都好好读一遍Effective C++ 系列,真是 ...

  9. python数据可视化——matplotlib 用户手册入门:使用指南

    参考matplotlib官方指南: https://matplotlib.org/tutorials/introductory/usage.html#sphx-glr-tutorials-introd ...

  10. Spring学习(3):Spring架构(转载)

    1. Spring架构图 核心容器:包括Core.Beans.Context.EL模块. ●Core模块:封装了框架依赖的最底层部分,包括资源访问.类型转换及一些常用工具类. ●Beans模块:提供了 ...