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

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

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

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

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

(注意:

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

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

)

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

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

5.重复步骤"1"

6.重复步骤"2"

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

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

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

点击打开链接

设计一个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的新特性线程池等。在这个项目中都很好的运用到了!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值