信号量解决协调进程同步问题(司机与售票员问题)
- 问题描述(在日常生活中司机和售票员的行为动作需要满足一定的规则 )
分析并发进程的交互点
1.首先我们将司机和售票员看成是2个进程,他们需要协调配合完成工作
2.我们需要找到进行并发执行过程中的交互点(一个进行肯定要等另一个进程做了才能接着往下做),在这个点上我们需要使用P v操作让他们按照正确的顺序同步执行(如果让其异步执行可能很大可能会出现错误的结果)
- 我们的期望情况
要达到上面的目的我们希望是【如果启动车辆在关闭车门之前执行将进行等待】【打开车门在停下车辆之前执行将进行等待】
对于信号量使用的分析
1.从上图中可以看出来在这个过程中有2个规则,也就说明我们的进程有2个交互点需要同步
2.信号量表示可用资源的数量,我们需要他们最开始就可用进入等待状态,就只能将【信号量设置为0】表示没有资源,在另一个进行相应的动作将信号量+1才能进行执行
- 实现图
这个代码不能正确运行,原因待查正 - Driver
package com.os;
public class Driver extends Thread{
@Override
public void run() {
//司机的动作流程
//1.车辆启动之前需要先关好门
SemaphoreUtils.P1(SemaphoreUtils.semaphore1);//P
System.out.println("启动车辆...");
System.out.println("正常行驶...");
System.out.println("到站停车...");
//2.车停下后提示售票员开门
SemaphoreUtils.V2(SemaphoreUtils.semaphore2);//V
}
}
- 售票员
package com.os;
public class TicketSeller extends Thread{
@Override
public void run() {
//售票员的动作流程
System.out.println("关闭车门...");
//1.关闭车门后提醒司机可用启动车辆
SemaphoreUtils.V1(SemaphoreUtils.semaphore1);//v操作
System.out.println("售票...");
//2.要等车停下才能开门
SemaphoreUtils.P2(SemaphoreUtils.semaphore2);//p操作
System.out.println("打开车门...");
}
}
- 工具类
package com.os;
//提供互斥锁的方法
public class SemaphoreUtils {
public static int semaphore1 = 0;
public static int semaphore2 = 0;
//V操作
public static void P1( int semaphore){
while (semaphore<=0){//说明没有资源可用
//自旋等待中
}
semaphore--;//信号量减1(标记资源用完了了
semaphore1 = semaphore;
System.out.println("semaphore1 = " + semaphore1);
}
//P操作
public static void V1( int semaphore){
semaphore++;//(标记资源可用了
semaphore1 = semaphore;
System.out.println("semaphore1 = " + semaphore1);
}
public static void P2( int semaphore){
while (semaphore<=0){//说明没有资源可用
//自旋等待中
}
semaphore--;//信号量减1(标记资源用完了了
semaphore2 = semaphore;
System.out.println("semaphore2 = " + semaphore2);
}
//P操作
public static void V2( int semaphore){
semaphore++;//(标记资源可用了
semaphore2 = semaphore;
System.out.println("semaphore2 = " + semaphore2);
}
}
- 测试类
package com.os;
public class SemaphoreTest {
public static void main(String[] args) {
Driver driver = new Driver();
TicketSeller ticketSeller = new TicketSeller();
driver.start();
ticketSeller.start();
}
}