Java高新技术之交通灯管理系统(java枚举,java线程池)

时间:2022-07-21 00:43:26



先看图,让我们先理清楚现实生活中十字路口的交通灯是怎么运行的:

我们如果认真观察会发现,十字路口有12条路线。十字路口每条方向上的路线的右转车辆是不考虑红绿灯的(即图中4条黑色路线,除了一些人多的特殊地段会设置)

1.首先假设你一到十字路口就看到,南北方向的直行车辆在行驶(图中两条绿色路线),其它三大路线(2条蓝色、2条红色和2条紫色)都在等待。

2.南北方向走完后,就轮到南北方向的左转路线(即蓝色路线),注意不是红色也不是紫色。(这时另外的三大路线在等待)

(注意:

a.南北、东西、南西、北东、东南、西北8条路线的车辆是同时交替放行的。解释:有南到北的,就有北到南的,例如图中,两条绿色的路线;有南到西,就有北到东,图中,两条蓝色路线等。

b.同方向等待车辆应该先放行直行车辆,再放行左转车辆。解释:例如南北方向的两条绿色路线在等待时(这时南北方向的左转车辆已经走完,蓝色路线),先放行东西方向的两条红色路线,等红色路线走完后,再放行东西方向的左转车辆,紫色路线

)

3.这时轮到东西方向的直行车辆行驶(即图中,两条红色路线),这时另外的三大路线在等待

4.最后轮到东西方向的左转车辆(即图中,两条紫色路线),这时另外的三大路线在等待。

5.重复步骤"1"

6.重复步骤"2"

7.不说了,你懂了........

Java高新技术之交通灯管理系统(java枚举,java线程池)

交通灯管理系统的项目需求:

1.异步随机生成按照各个路线行驶的车辆

例如:

a.由南向北去的车辆....直行车辆(图中,绿色路线)

b由西向南去的车辆....右转车辆(图中,黑色路线,其实认真观察生活会发现,十 字 路口的每个右转弯的灯永远都是绿的或者没有设置)

c.由东向南去的车辆....左转车辆(图中,紫色路线)

..........................

2.信号灯忽略黄灯,只考虑红灯和绿灯

3.应该考虑左转车辆控制信号灯,右转车辆不受信号灯控制

4.具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑一样,不考虑特殊情况下的控制逻辑

5.每辆车通过路口的时间设置为1(提示:可通过线程的sleep方法模拟)

6.随机生成的车辆时间间隔以及红绿灯交换的时间间隔自定,可以设置

面向对象的分析与设计:

1.每条线路上都会出现多辆车,路线上要随机增加新的车,在灯变绿期间要每秒钟减少一辆车

设计一个Road类来表示路线,每个Road对象代表一条路线,总共12条,即系统中总共要产生12Road实例对象

每条路线上随机增加新的车辆,增加到一个集合中保存

每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存的集合中的第一辆车移除,即表示车穿过路口

下面看Road代码(具体分析看代码注释):

public class Road {

//定义一个集合用来存储每条路线上的车辆
private List<String> vehicles=new ArrayList<String>();
//路线的名字:例如S2N N2S E2W W2W ....
private String name;
public Road(String name)
{
this.name=name;
//随机的往list集合中增加车辆,即多少辆车开到哪条路线路上
ExecutorService pool=Executors.newSingleThreadExecutor();
pool.execute(new Runnable() {

@Override
public void run() {
for(int i=1;i<=1000;i++)
{
try {
//往集合中增加车辆不可能一下子就来了1000辆车吧,所以要每隔n秒增加一辆车(这个n是指1到10之间的随机数)
Thread.sleep((new Random().nextInt(10)+1)*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//哪条路线上的第几辆车
vehicles.add(Road.this.name+"_"+i);
}
}
});

//定义一个线程池,它是支持周期性的任务执行。
//这个线程池的作用是:你不可能车开到路上就不走了吧(堵车或车祸不考虑),所以要定期的让车行驶
//即定期的让车穿过绿灯
ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);
//参数:第一个,要执行的线程;第二个,每隔多长时间执行一次线程;第三个,执行的周期;第四个,指定第二个和第三个参数代表的数值,秒
timer.scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
//首先要判断路线上是否有车,没车你还搞什么!!
if(vehicles.size()>0)
{
//获取当前路线上的灯是否为绿,是绿就让这条路线上的车辆穿过
boolean lightGreen=Lamp.valueOf(Road.this.name).getLighted();
if(lightGreen)
{
System.out.println(vehicles.remove(0)+".......穿过绿灯");
}
}
}
},
10,
10,
TimeUnit.SECONDS);

}
}

2.每条路线每隔一秒都会检查控制本路线的灯是否为绿,一个灯有绿变红时,应该将下一个方向的灯变绿(关于枚举可以看我才这篇博客

黑马程序员_JAVA之Myeclipse中Junit、静态导入、枚举和单例设计模式)

设计一个Lamp类来表示一个交通灯,每个交通灯都维护一个状态,绿或者红,每个交通灯要有变亮和变黑的方法,并且能返回自己的红绿状态

总共有12条路线,所以,系统中总共要产生12个交通灯。右转弯的路线本来不受等控制,但是为了让程序采用同意思的处理方式,

故假设出有四个右转弯的灯,只是这些灯为常绿,即永远不变红。除了右转弯方向的其他8条路线的灯,它们是两两成对的,可以归为4组,

所以,在编程处理时,只要从这4组中各取出一个灯,对这4个灯依次循环变绿,与这4个灯方向对应的灯则随之一同变化,

因此Lamp类中要有一个变量来记住自己相反方向的灯,在一个Lamp对象的变绿和变红方法中,将对应方向的灯也变绿和变红。

每个灯变红时,都伴随着下一个等的变红,Lamp类中还用一个变量来记住自己的下一个灯。

下面看Lamp代码(具体看注释):

public enum Lamp {

//这里只考虑南到北、南到西、东到西和东到南,因为每个方向上的行驶路线是两两对应的。
//(参数分别是:对应的灯、下一个灯,自己的灯)
S2N("N2S","S2W",false),S2W("N2E","E2W",false),E2W("W2E","E2S",false),E2S("W2N","S2N",false),
N2S(null,null,false),N2E(null,null,false),W2E(null,null,false),W2N(null,null,false),
//下面都是每个方向上的右转弯,所以不考虑对应的灯和下一个灯,并且右转的灯永远都是绿的
S2E(null,null,true),E2N(null,null,true),N2W(null,null,true),W2S(null,null,true);

//定义一个变量,记录每条路线上的每个方向上的灯的状态,true为绿,false为红
private boolean lighted;
//每条路线对应的等。例如:S2N对应的灯是N2S
private String oppositeLight;
//每条路线对应的下一条路线的灯,例如:S2N路线对应的下一条路线S2W对应的灯
private String nextLight;

private Lamp(String oppositeLight,String nextLight,boolean lighted){
this.oppositeLight=oppositeLight;
this.nextLight=nextLight;
this.lighted=lighted;
}
public boolean getLighted()
{
return lighted;
}

//将灯设置为绿
public void setGreen()
{
this.lighted=true;
//判断是否有对应的灯
if(oppositeLight!=null){
Lamp.valueOf(oppositeLight).setGreen();
}
System.out.println(name()+" lamp is green, 您将看到有6个方向的车可以行使");

}

//将灯设置为红,并且将下一条路线的灯设置为绿
public Lamp setRed()
{
this.lighted=false;
//判断是否有对应的灯
if(oppositeLight!=null){
Lamp.valueOf(oppositeLight).setRed();
}
//将下一个灯变为绿色,并且返回出去
Lamp nextLlight=null;
if(nextLight!=null){
nextLlight=Lamp.valueOf(nextLight);
System.out.println("绿灯从"+name()+" --------切换为------->"+nextLight);
nextLlight.setGreen();

}

return nextLlight;
}
}

3.要让每条路线上的红绿灯的系统运行起来,还需要另外一个控制整个交通系统的类,LampController

控制每条线路上红绿灯的状态,每隔10秒钟变化一次。

下面看LampController代码(具体看注释)

public class LampController {

//临时变量,记住当前路线车的状态,以及设置红绿灯的状态
private Lamp currentLamp;

public LampController(){
//总得有个开始的路线吧,所以这里设置南到北路线的开始执行,
currentLamp=Lamp.S2N;
//将南到北路线上的灯设置为绿色,并且setGreen方法内部会将S2N的对应路线即N2S的灯也设置为绿色
currentLamp.setGreen();

ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable(){
public void run(){
//10秒钟以后将这条路线上的灯设置为红色,并且将对应路线上的灯也设置为红色,
//并且将下一条路线上的灯设置为绿色,并返回一个Lamp枚举的对象,
//这样整个交通灯的系统就跑起来了
currentLamp=currentLamp.setRed();
}
},
10,
10,
TimeUnit.SECONDS);
}
}

4.下个测试类:MainTest(具体看代码注释)

public class MainTest {

public static void main(String[] args) {
/*
第一步:让每个方向上都有车
1.这里是利用线程的方式让每个方向上都有机会增加车辆,因为有12条路线,这里采用for循环的方式
创建每条路线上的车,当一new Road(directions[i]);时就会倒Road类中的构造函数中,
构造函数有两个线程池,一个是增加车辆,另一个是让车穿过绿灯,
2.但是这时会阻塞在"boolean lightGreen=Lamp.valueOf(Road.this.name).getLighted();"这!!!
为什么?
因为它要判断当前方向上的灯是否是绿色的,可是整个交通灯系统没有跑起来啊,所以这里的线程会阻塞,看第二步:
* */
//将12条路线都加到Road中的线程池中,让每条路线上都有车,再说
String[] directions=new String[]{
"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"
};

//这里是利用for循环创建12个线程,一个一个创建太麻烦了,所以用for循环
for(int i=0;i<directions.length;i++){
new Road(directions[i]);
}

/*第二步
让整个交通系统运行起来吧!
控制每条路线上的红绿灯,其实这里只是控制了"S2N","S2W","E2W","E2S"这四条路线,
它们各自对应的路线的灯都是交替运行的,而每条路线的右转弯是不考虑的
1.当一new LampController();时会到LampController类中的构造函数中,
构造函数同样有个线程池,在线程池运行前有个"currentLamp.setGreen();"这时整个交通系统就已经跑起来了
2.当执行到线程池那块代码时,它会每隔10秒将当前路线上的灯设置为红色(即currentLamp=currentLamp.setRed();),
灯设置为红色后,该函数会返回一个Lamp对象,这就是下一个路线上的灯了
3.第一步中的线程再跑,第二步这里的线程也在跑,所以整个系统就OK了!!!
* */
new LampController();

}

}
5.关于线程池可以查看这篇博客点击打开链接

总结:

       这个交通灯系统是跟着张老师的视频走了两遍才明白的啊!想做好这个交通灯,你得对现实生活中十字路口的交通有所了解。就像一开始我解释的那样!其实我也是问了我考驾照的同学的!让后就是把握住”一切皆对象”的道理来做就行啦!12条路线!!!你把它看做一个对象;各个方向上的灯你把它看做对象;还有最后一个LampController这个类。

       做了这个项目之后感觉以前学的很零散的东西都整合到一起了,也知道学的那些知识点怎么用了。例如:枚举,在这个项目中可不是简单的定义一个枚举啊,中间用到了枚举中的构造方法,属性和普通方法,如果你可以把这个项目吃透,那么枚举就不成问题了!再例如,java1.5的新特性线程池等。在这个项目中都很好的运用到了!!!