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. 20155331 《信息安全技术概论》实验二 Windows口令破解

    20155331 <信息安全技术概论>实验二 Windows口令破解 [实验目的] 了解Windows口令破解原理 对信息安全有直观感性认识 能够运用工具实现口令破解 [实验原理] 口令破 ...

  2. removeAttribute与removeAttributeNode的区别

    1.removeAttributeNode() 方法删除指定的属性,并以 Attr Node 对象返回被删除的属性. 例: <!DOCTYPE html><html><b ...

  3. easyui -validatebox 验证框加载

    问题: easyui验证狂框有时会验证输入字符的位数,或者验证有效字符组合 解决: 使用easyui的验证框,继承验证框,指定输入框为验证框即可 $(function(){ $.extend($.fn ...

  4. 【AHOI2013】差异

    题面 题解 $ \because \sum_{1 \leq i < j \leq n} i + j = \frac{n(n-1)(n+1)}2 $ 所以只需求$\sum lcp(i,j)$即可. ...

  5. dp合集 广场铺砖问题&&硬木地板

    dp合集 广场铺砖问题&&硬木地板 很经典了吧... 前排:思想来自yali朱全民dalao的ppt百度文库免费下载 后排:STO朱全民OTZ 广场铺砖问题 有一个 W 行 H 列的广 ...

  6. 【RAC搭建报错】libcap.so.1:cannot open shared object file

    原文参考:http://blog.csdn.net/siyanyanyanyai/article/details/45306595 http://orax.blog.sohu.com/26207226 ...

  7. jenkins自动打包部署linux

    需要用到2个插件. git parameter:用于参数化构建时选择分支. Publish Over SSH:用于上传jar包和操作tomcat 1.先在系统设置添加要连接的linux服务器,使用用户 ...

  8. nginx基础配置加基础实战演示

    目录 基本配置 设置用户 工作衍生进程数 错误日志存放路径 pid文件存放路径 设置最大连接数 http->server gzip 字符编码 nginx的基本格式 实战配置 虚拟主机配置 开始配 ...

  9. JavaScript 中函数的参数

    functionName(parameter1, parameter2, parameter3) { // 要执行的代码…… } 参数规则 JavaScript 函数定义时形参没有指定数据类型. Ja ...

  10. Linux中新增硬盘的分区,格式化与挂载

    Linux中新增硬盘的分区,格式化与挂载 本篇教程内容为怎样对Linux新增硬盘进行挂载,所以如果有准备新增硬盘但是有各种问题的,请参看本篇教程. 我们先说说什么是挂载? 我们知道Linux中的所有设 ...