转---秒杀多线程第十二篇 多线程同步内功心法——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");//
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操作上 (续)的更多相关文章
- 多线程同步内功心法——PV操作上(未完待续。。。)
阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...
- 多线程面试题系列(12):多线程同步内功心法——PV操作上
上面的文章讲解了在Windows系统下实现多线程同步互斥的方法,为了提高在实际问题中分析和思考多个线程之间同步互斥问题的能力,接下来将讲解PV操作,这也是操作系统中的重点和难点.本文将会先简要介绍下P ...
- C++第五十二篇 -- 多线程之消息传递
主线程向子线程发送消息 参考链接:https://www.cnblogs.com/ranjiewen/p/5729539.html 1. 创建线程语句 HANDLE hThread; DWORD dw ...
- “全栈2019”Java多线程第二十二章:饥饿线程(Starvation)详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第十二章:后台线程setDaemon()方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第十六章:同步synchronized关键字详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- 解剖SQLSERVER 第十二篇 OrcaMDF 行压缩支持(译)
解剖SQLSERVER 第十二篇 OrcaMDF 行压缩支持(译) http://improve.dk/orcamdf-row-compression-support/ 在这两个月的断断续续的开发 ...
- 第十二篇 SQL Server代理多服务器管理
本篇文章是SQL Server代理系列的第十二篇,详细内容请参考原文 在这一系列的上一篇,我们查看了维护计划,一个维护计划可能会创建多个作业,多个计划.你还简单地看了SSIS子系统,并查看了维护计划作 ...
- 第十二篇 Integration Services:高级日志记录
本篇文章是Integration Services系列的第十二篇,详细内容请参考原文. 简介在前一篇文章我们配置了SSIS内置日志记录,演示了简单和高级日志配置,保存并查看日志配置,生成自定义日志消息 ...
随机推荐
- CF 1083 A. The Fair Nut and the Best Path
A. The Fair Nut and the Best Path https://codeforces.com/contest/1083/problem/A 题意: 在一棵树内找一条路径,使得从起点 ...
- jsp命名规则
jsp也用驼峰规则命名即可,不要使用下划线,否则在tomcat中容易出现解析错误
- 一、EnterpriseFrameWork框架总体介绍
EnterpriseFrameWork框架是自己在工作之余的得意之作,经过了几年时间的不断重构,现在终于有了现在的样子:刚开始只是为了方便开发WEB系统,随着项目越做越多,新的功能也就不断补充进去,补 ...
- VS2008 "无法找到资源编译器dll 请确保路径正确"
系统环境:windows 8.1 企业版 x64 (装有 .NET 2.0 / 3.5 / 4.0 / 4.5) 安装前确认系统已安装 .NET 2.0 / 3.5 .在安装时,最好是默认安装,并且 ...
- 2018百度之星开发者大赛-paddlepaddle学习
前言 本次比赛赛题是进行人流密度的估计,因为之前看过很多人体姿态估计和目标检测的论文,隐约感觉到可以用到这次比赛上来,所以趁着现在时间比较多,赶紧报名参加了一下比赛,比赛规定用paddlepaddle ...
- 使用Mininet创建网络拓扑
使用Mininet创建Topo Python脚本实现创建拓扑 #coding:utf-8 from mininet.net import Mininet from mininet.topo impor ...
- Catch That Cow:BFS:加标记数组:不加标记数组
Catch That Cow Problem Description Farmer John has been informed of the location of a fugitive cow a ...
- linux下各文件夹的结构说明及用途介绍(转载)
详细介绍文档 转载文章路径 /bin:二进制可执行命令. /dev:设备特殊文件. /etc:系统管理和配置文件. /etc/rc.d:启动的配 置文件和脚本. /home:用户主目录的基点,比如用户 ...
- [笔记] centos6.6编译安装httpd2.4.10
系统安装包是CentOS-6.6-x86_64-minimal.iso 查看一下uname信息 [root@localhost ~]# uname -a Linux localhost.localdo ...
- ElasticSearch之CURL操作(有空再去整理)
https://www.cnblogs.com/jing1617/p/8060421.html ElasticSearch之CURL操作 CURL的操作 curl是利用URL语法在命令行方式下工 ...