继上一次的Dekker算法的Peterson算法之后,我发现不能复制代码块是因为浏览器的问题,嘿嘿。上次结束有提到信号量的问题,信号量可以堪称是解决同步和互斥的最棒的处理方法。
接下来我们又引入一个经典的例子。
“单生产者和单消费者有限缓存的解决方法。”
在一个仓库有十个货架可以放置十个产品,一开始是没有产品的,货架放满了之后生产者不可以再放置产品,消费者不可以在没有产品的时候取出产品。
我们有上面信息可以得出我们的临界值为:①仓库的货架的剩余量,初值为10;②仓库内的产品,初值为0。
package class1;
import java.util.concurrent.Semaphore;
public class Semaphore; {
public static void main(String[] args) {
Cangku cangku = new Cangku();
Thread p1 = new Producter(cangku);
Thread c1 = new Customer(cangku);
p1.start();
c1.start();
}
}
class RundomData{
public static int getRundomDate() {
return (int)(Math.round(Math.random()*100)); //生产一个一百以内的随机数
}
}
class Sem{
public static final Semaphore WEIZHI=new Semaphore(10); //仓库中产品的位置数量
public static final Semaphore CHANPIN= new Semaphore(0); //仓库中可以用于消费的产品数
}
class Cangku{
private int [] storeRack = new int[10]; //仓库货架初值为10
private int put_index=0; //放入产品下标
private int get_index=0; //取出产品下标
public void put(int data) { //生产者执行放置产品
storeRack[put_index]=data; //将产品放入
System.out.println("生产者将产品"+storeRack[put_index]+"放入了"+put_index+"位置");
//输出语句,输出生产者生产信息。
try {
Thread.sleep(300); //随机休息时间,方便自己查看结果,不至于跳转的太快。
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
put_index=(put_index+1)%storeRack.length; //货架放满后从头开始。
}
public int get() { //消费者执行取出产品
int product = storeRack[get_index]; 将产品取出
System.out.println("\t\t\t\t"+"消费者将产品"+storeRack[get_index]+"从"+get_index+"位置取出");//输出语句,输出消费者取出产品信息。\te 作用是使输出结果生产者和消费者信息分开。
get_index=(get_index+1)%storeRack.length;//从头开始取
return product; //返回取出的产品。
}
}
class Producter extends Thread{
private Cangku cangku ;
public Producter(Cangku cangku) {//构造函数
this.cangku=cangku;
}
public void run() {
while (true) { //因为生产产品是不需要临界资源的所以这里设置死循环表明可以无限制生产产品
int data = RundomData.getRundomDate(); 这里涉及了随机数的问题,不理解的自行百度,在这里不做解释,只要知道我们的产品是随机数就可以,
try {
Sem.WEIZHI.acquire(); // 信号量临界资源位置的“P”操作,减少一个位置
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
cangku.put(data);// 将产品放入仓库货架
Sem.CHANPIN.release(); // 信号量临界资源产品的“V”操作,释放一个产品。
}
}
}
class Customer extends Thread{
private Cangku cangku ;
public Customer(Cangku cangku) {
this.cangku=cangku;
}
public void run() {
while(true) {//因为消费产品是不需要临界资源的所以这里设置死循环表明可以无限制取出产品
try {
Sem.CHANPIN.acquire(); // 信号量临界资源产品的“P”操作,增加一个产品。
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int product = cangku.get(); //将产品从货架中取出
Sem.WEIZHI.release(); // 信号量临界资源位置的“V”操作,释放一个位置。
}
}
}
信号量知识点
信号量–信号量是解决进程互斥问题的最优秀的解决方法
(1) 定义:
Struct Semaphore //信号量用于描述资源
{
int value ; // 必须有一个非负的初值,只能初始化一次
&PCB queue; //该信号量的等待队列
}
(2)P(wait) 、V(signal)操作
(3)P、V操作注意事项
1.P,V操作必须成对出现(不一定是1:1关系)
2.互斥信号量的PV操作出现在同一进程中,同步信号量的PV操作出现在不同进程中。
3.如果出现连续P操作,同步P一定要放在互斥P前面(否则可能出现死锁)
(4)信号量的物理意义:
a. S.value >0 s.value表示可用资源个数
b. S.value=0 表示无资源,无进程等待
c. S.value<0 |S.value|表示等待该资源进程的个数
(5)用信号量解决经典同步问题(生产者消费者问题、读者写者问题)
下一步多生产者多消费者有限资源。o( ̄▽ ̄)ブ 明天也要加油鸭。