首页 > 编程 > Java > 正文

java 多线程交通信号灯模拟过程详解

2019-11-26 08:50:56
字体:
来源:转载
供稿:网友

这学期我们java课程的课程设计项目----交通信号灯的线程设计

  • 实验目的:多线程设计,同步机制
  • 题意 设计一个交通信号灯类:
    • 变量:位置、颜色(红、黄、绿)、显示时间(秒)。
    • 方法:切换信号灯。
  • 创建并启动两个线程(东西向、南北向)同时运行。
  •  实验要求
    • 设计线程。
    • 设计路口信号灯示意图界面。
    • 进一步将每个方向的信号灯分成3种车道灯:左转、直行和右转。
    • 根据车流量进行时间的模糊控制。

在课程设计的开始并没有仔细看老师的要求,只知道是交通信号灯。然后就开始各种找资料,百度,网上大量的关于红绿灯的设计都是参考张孝祥老师的教程,大概的设计方法是创建了三个类 lamp、road、lampcontrol。

然鹅......对.....然鹅又来了,在查了大概两天资料后,我又反过来看了一遍老师发的设计要求.....这这这.....,光控制灯就行了啊,不要车的啊,捂脸...

所以设计思路马上就变得清晰,根据张老师的做法,每个路口都有三个灯,分别为左转、直行、右转,所以一共有12盏灯。按照要求,右转灯为常亮灯,左转和直行灯才有红绿交替。在除去右转灯的八个灯里面,又可以分为四组可以两两匹配的灯,分别为东西左转南北(平行转垂直)、南北直行(垂直通行)、南北左转东西(垂直转平行)、东西直行(平行通行)。

于是我给这个12个灯编了个号:

emmm 大概就是这样,但是跟生活中的红绿灯不同,生活中的都是看对面路口的灯,我们这里是模拟嘛....就各个路口用各个路口的灯呗.....

大致解释一下,

1号灯为由南向西的左转灯,2号灯为由南向北的直行灯,3号灯为由南向东的右转灯。

4号灯为由东向北的右转灯,5号灯为由东向西的直行灯,6号灯为由东向南的左转灯。

7号灯为由北向西的右转灯,8号灯为由北向南的直行灯,9号灯为由北向东的左转灯。

10号灯为由西向北的左转灯,11号灯为由西向东的直行灯,12号灯为由西向南的右转灯。

然后根据匹配的原则,大概就是这么一张图:

我们就可以得到:

这四组信号灯。

到这里我们思路就很清晰了,我们可以分别为每一组信号灯开一个进程,然后使四个进程循环交替进行就实现了绿灯的转换。使用了程的同步技术。

当然,我们都已经开了四个进程了,为了锦上添花,我当然不介意再加个小车了hhhhhh

实验结果图:

源代码:

light类:

package traffic; public class light {	int x,y;         //灯在画布上的位置	boolean status;      //灯的状态	public light(int x,int y,boolean islight) {		this.x=x;        		this.y=y;		this.status=islight;	}	public void setlight(boolean sta) {    //对外接口更改灯的状态		this.status=sta;	}}

lamp类:

package traffic; public class lamp implements Runnable {	light opposite, now;      //相互匹配的两个灯	int greentime;         //绿灯亮的时间	int name;            //编组	boolean status;         //状态	static Object lock = new Object(); 	public lamp(light l0, light l2,int gt, boolean st, int name) {		now = l0;		opposite = l2;		status = st;		greentime = gt;		this.name = name;		lightstatues();	} 	public void change() { 		this.status = !(this.status);		lightstatues();	}	public void setgreentime(int time) {		this.greentime=time;	}	public int getgreentime() {		return this.greentime;	}	public void lightstatues() {		opposite.setlight(status);		now.setlight(status);	} 	public void run() {		while (true) {			synchronized (lock) {        //使用synchronized实现进程间的互斥				if (name == mainclass.panel.islight) {      //使用辅助变量实现进程按顺序循环					//System.out.println("now is: "+name);					change();					mainclass.panel.repaint();					try {						Thread.sleep(greentime);					} catch (InterruptedException e) {						e.printStackTrace();					}					lock.notifyAll();        //唤醒其他进程					change();					mainclass.panel.LampChange();					mainclass.panel.repaint();					try {						lock.wait();					} catch (InterruptedException e) {						e.printStackTrace();					}				} else {					try {						lock.wait();      //挂起进程					} catch (InterruptedException e) {						e.printStackTrace();					}				}			}		}	}}

Mypanel类:

package traffic; import java.awt.Color;import java.awt.Graphics;import java.util.ArrayList;import java.util.Random;import javax.swing.JPanel;public class Mypanel extends JPanel {	light l0,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12;   //十二个灯	lamp lamp1,lamp2,lamp3,lamp4;           //四组信号灯	static int islight;                //实现进程循环的辅助变量	Random r=new Random();	static public ArrayList<light> lightlist= new ArrayList<light>();  //使用list方便遍历每个灯	static public ArrayList<car> carlist= new ArrayList<car>();          //方便遍历每个车	public Mypanel() {		// TODO Auto-generated constructor stub		l0=addlist(l0, 212, 316, false);		l2=addlist(l2, 242, 316, false);			l3=addlist(l3, 272, 316, true);			l4=addlist(l4, 316, 116, true);			l5=addlist(l5, 316, 146, false);			l6=addlist(l6, 316, 176, false);			l7=addlist(l7,116 , 70, true);			l8=addlist(l8, 146, 70, false);			l9=addlist(l9, 176, 70, false);			l10=addlist(l10, 70, 212, false);			l11=addlist(l11, 70, 242, false);			l12=addlist(l12, 70, 272, true				lamp1=new lamp(l9,l0,2000,false,0);		lamp2=new lamp(l11,l5,2000,false,1);		lamp3=new lamp(l10,l6,2000,false,2);		lamp4=new lamp(l8,l2,2000,false,3); 		islight = 0 ;				Thread t1=new Thread(lamp1);      //创建并启动线程		Thread t2=new Thread(lamp2);		Thread t3=new Thread(lamp3);		Thread t4=new Thread(lamp4);		t1.start();		t2.start();		t3.start();		t4.start();	}	light addlist(light a,int x,int y,boolean sta) {		a=new light(x,y,sta);		lightlist.add(a);		return a;	}	public void addcar() {          //生成小车		int now,next;		now=r.nextInt(4);		next=r.nextInt(4);		car testcar=null;		while(now==next) 			next=r.nextInt(4);		switch(now) {		case 0:			testcar=new car(now,next,l0,l2,l3);			break;		case 1:			testcar=new car(now,next,l6,l5,l4);			break;		case 2:			testcar=new car(now,next,l9,l8,l7);			break;		case 3:			testcar=new car(now,next,l10,l11,l12);			break;		}		carlist.add(testcar);		Thread catt=new Thread(testcar);		catt.start();	}	public void LampChange() {		islight=(islight+1)%4;	}	public void paint(Graphics g) {		super.paint(g);				g.setColor(Color.darkGray);    //画路		g.fillRect(0, 100, 400, 6);		g.fillRect(0, 300, 400, 6);		g.fillRect(100, 0, 6, 400);		g.fillRect(300, 0, 6, 400);		g.setColor(Color.gray);		g.fillRect(0, 200, 400, 2);		g.fillRect(200, 0, 2, 400);		g.setColor(Color.blue);			g.setColor(Color.black);     //画信号灯板		g.fillRect(202,306, 100, 40);		g.fillRect(306,106, 40, 100);		g.fillRect(106,60, 100, 40);		g.fillRect(60,202,40, 100);		light temp;		car buf;		for(int i=0;i<carlist.size();i++) {   //画车			buf=carlist.get(i);			g.setColor(Color.BLUE);			g.fillRect(buf.x, buf.y, 50, 50);		}		for(int i=0;i<lightlist.size();i++) {    //画灯			temp=lightlist.get(i);			if(temp.status)				g.setColor(Color.green);			else				g.setColor(Color.RED);			g.fillOval(temp.x, temp.y, 20, 20);		}	}}

welcomepanel类:

package traffic; import java.awt.Color;import java.awt.Font;import java.awt.Graphics;import javax.swing.JPanel; public class welcomepanel extends JPanel implements Runnable{  //开始界面	int info = 0;	Boolean isLive=true; 	public void paint(Graphics g) {		super.paint(g);		g.fillRect(0, 0, 420,450);		g.setColor(Color.red);		g.setFont(new Font("微软雅黑", Font.BOLD, 30));		if (info % 2 == 0) {			g.drawString("多线程红绿灯模拟", 80, 150);		}	} 	public void run() {		// TODO Auto-generated method stub		while (true) {			try {				Thread.sleep(100);			} catch (InterruptedException e) {				// TODO Auto-generated catch block				e.printStackTrace();			}			info++;			this.repaint();			if (isLive == false) {				break;			}		}	}	}

set类:

package traffic; import java.awt.FlowLayout;import java.awt.GridLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener; import javax.swing.JButton;import javax.swing.JDialog;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JOptionPane;import javax.swing.JPanel;import javax.swing.JTextField; public class set extends JFrame implements ActionListener {   //设置界面  JLabel lab1,lab2,lab3,lab4;  JTextField jtext1,jtext2,jtext3,jtext4;  JPanel panel1,panel2,panel3,panel4;  JButton jb1,jb2;  int time1,time2,time3,time4;	public set(){   	lab1=new JLabel("南北左转东西:");  	lab2=new JLabel("东西直行:");  	lab3=new JLabel("东西左转南北:");  	lab4=new JLabel("南北直行:");  	time1=mainclass.panel.lamp1.getgreentime();  	time2=mainclass.panel.lamp2.getgreentime();  	time3=mainclass.panel.lamp3.getgreentime();  	time4=mainclass.panel.lamp4.getgreentime();  	jtext1=new JTextField(String.valueOf(time1));  	jtext2=new JTextField(String.valueOf(time2));  	jtext3=new JTextField(String.valueOf(time3));  	jtext4=new JTextField(String.valueOf(time4));  	  	jb1=new JButton("确定");  	jb1.addActionListener(this);  	jb2=new JButton("取消");  	jb2.addActionListener(this);  	  	this.setLayout(new GridLayout(5,2,10,5));  	this.add(lab1);  	this.add(jtext1);  	this.add(lab2);  	this.add(jtext2);  	this.add(lab3);  	this.add(jtext3);  	this.add(lab4);  	this.add(jtext4);  	this.add(jb1);  	this.add(jb2);  	  	this.setLocationRelativeTo(null);   	this.setSize(200, 200);   	this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);  	this.setResizable(false);    this.setVisible(true);   }  public void actionPerformed(ActionEvent e) {  	if(e.getSource()==jb1) {  		  		if(jtext1.getText().length()==0||jtext2.getText().length()==0||jtext3.getText().length()==0||jtext4.getText().length()==0)   			JOptionPane.showMessageDialog(this, "请输入完整数据!", "错误", JOptionPane.INFORMATION_MESSAGE);  		else {  			mainclass.panel.lamp1.setgreentime(Integer.parseInt(jtext1.getText()));  			mainclass.panel.lamp2.setgreentime(Integer.parseInt(jtext2.getText()));  			mainclass.panel.lamp3.setgreentime(Integer.parseInt(jtext3.getText()));  			mainclass.panel.lamp4.setgreentime(Integer.parseInt(jtext4.getText()));  			this.dispose();  		}  	}else if(e.getSource()==jb2){  		this.dispose();  	}  }}

mainclass主类:

package traffic;import java.awt.event.ActionEvent;import java.awt.event.ActionListener; import javax.swing.JFrame;import javax.swing.JMenu;import javax.swing.JMenuBar;import javax.swing.JMenuItem;import javax.swing.JOptionPane; public class mainclass extends JFrame implements ActionListener{	static Mypanel panel;		JMenuBar jmb;	JMenu jm1, jm2;	JMenuItem jmi1, jmi2,jmi3,jmi4;	welcomepanel sp;		mainclass(){		this.setTitle("traffic lamp");		this.setSize(420,450);		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);		jmb=new JMenuBar();			jm1=new JMenu("控制");		jm2=new JMenu("设置");			jmi1=new JMenuItem("开始模拟");		jmi1.addActionListener(this);		jmi2=new JMenuItem("退出模拟");		jmi2.addActionListener(this);		jmi3=new JMenuItem("随机生成小车");		jmi3.addActionListener(this);		jmi4=new JMenuItem("更改绿灯时间");		jmi4.addActionListener(this);		jm1.add(jmi1);		jm1.add(jmi2);		jm1.add(jmi3);		jm2.add(jmi4);		jmb.add(jm1);		jmb.add(jm2);				this.setJMenuBar(jmb);				sp=new welcomepanel();		Thread t=new Thread(sp);		t.start();		this.setContentPane(sp);				this.setLocationRelativeTo(null); 		this.setResizable(false);		this.setVisible(true);	}		public void actionPerformed(ActionEvent e) {		if(e.getSource()==jmi1) {			sp.isLive=false;			this.remove(sp);			panel = new Mypanel();			this.setContentPane(panel);			this.setVisible(true);		}else if(e.getSource()==jmi2) {			System.exit(0);		}else if(e.getSource()==jmi3) {			if(panel==null)  			JOptionPane.showMessageDialog(this, "请开始模拟再生成小车", "错误", JOptionPane.INFORMATION_MESSAGE);			else panel.addcar();		}else if (e.getSource() == jmi4) {			if(mainclass.panel==null)  			JOptionPane.showMessageDialog(this, "请开始模拟再进行设置", "错误", JOptionPane.INFORMATION_MESSAGE);			else new set();			}		}	public static void main(String[] args) {		new mainclass();	}}

多线程正确性测试:

我们在lamp类的run()方法中添加了一句控制台打印命令,每次进程运行时即会打印此进程的name成员

正确的打印结果应该为 0-1-2-3-4-0-1-2-3-4-.......-1-2-3-....

控制台的输出结果为:

符合预测结果,实验完成!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表