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();
}
}
}