java 多線程交通信號燈模擬過程詳解
這學(xué)期我們java課程的課程設(shè)計項(xiàng)目----交通信號燈的線程設(shè)計
- 實(shí)驗(yàn)?zāi)康模憾嗑€程設(shè)計,同步機(jī)制
- 題意 設(shè)計一個交通信號燈類:
- 變量:位置、顏色(紅、黃、綠)、顯示時間(秒)。
- 方法:切換信號燈。
- 創(chuàng)建并啟動兩個線程(東西向、南北向)同時運(yùn)行。
- 實(shí)驗(yàn)要求
- 設(shè)計線程。
- 設(shè)計路口信號燈示意圖界面。
- 進(jìn)一步將每個方向的信號燈分成3種車道燈:左轉(zhuǎn)、直行和右轉(zhuǎn)。
- 根據(jù)車流量進(jìn)行時間的模糊控制。
在課程設(shè)計的開始并沒有仔細(xì)看老師的要求,只知道是交通信號燈。然后就開始各種找資料,百度,網(wǎng)上大量的關(guān)于紅綠燈的設(shè)計都是參考張孝祥老師的教程,大概的設(shè)計方法是創(chuàng)建了三個類 lamp、road、lampcontrol。
然鵝......對.....然鵝又來了,在查了大概兩天資料后,我又反過來看了一遍老師發(fā)的設(shè)計要求.....這這這.....,光控制燈就行了啊,不要車的啊,捂臉...
所以設(shè)計思路馬上就變得清晰,根據(jù)張老師的做法,每個路口都有三個燈,分別為左轉(zhuǎn)、直行、右轉(zhuǎn),所以一共有12盞燈。按照要求,右轉(zhuǎn)燈為常亮燈,左轉(zhuǎn)和直行燈才有紅綠交替。在除去右轉(zhuǎn)燈的八個燈里面,又可以分為四組可以兩兩匹配的燈,分別為東西左轉(zhuǎn)南北(平行轉(zhuǎn)垂直)、南北直行(垂直通行)、南北左轉(zhuǎn)東西(垂直轉(zhuǎn)平行)、東西直行(平行通行)。
于是我給這個12個燈編了個號:

emmm 大概就是這樣,但是跟生活中的紅綠燈不同,生活中的都是看對面路口的燈,我們這里是模擬嘛....就各個路口用各個路口的燈唄.....
大致解釋一下,
1號燈為由南向西的左轉(zhuǎn)燈,2號燈為由南向北的直行燈,3號燈為由南向東的右轉(zhuǎn)燈。
4號燈為由東向北的右轉(zhuǎn)燈,5號燈為由東向西的直行燈,6號燈為由東向南的左轉(zhuǎn)燈。
7號燈為由北向西的右轉(zhuǎn)燈,8號燈為由北向南的直行燈,9號燈為由北向東的左轉(zhuǎn)燈。
10號燈為由西向北的左轉(zhuǎn)燈,11號燈為由西向東的直行燈,12號燈為由西向南的右轉(zhuǎn)燈。
然后根據(jù)匹配的原則,大概就是這么一張圖:

我們就可以得到:
這四組信號燈。
到這里我們思路就很清晰了,我們可以分別為每一組信號燈開一個進(jìn)程,然后使四個進(jìn)程循環(huán)交替進(jìn)行就實(shí)現(xiàn)了綠燈的轉(zhuǎn)換。使用了程的同步技術(shù)。
當(dāng)然,我們都已經(jīng)開了四個進(jìn)程了,為了錦上添花,我當(dāng)然不介意再加個小車了hhhhhh
實(shí)驗(yàn)結(jié)果圖:

源代碼:
light類:
package traffic;
public class light {
int x,y; //燈在畫布上的位置
boolean status; //燈的狀態(tài)
public light(int x,int y,boolean islight) {
this.x=x;
this.y=y;
this.status=islight;
}
public void setlight(boolean sta) { //對外接口更改燈的狀態(tài)
this.status=sta;
}
}
lamp類:
package traffic;
public class lamp implements Runnable {
light opposite, now; //相互匹配的兩個燈
int greentime; //綠燈亮的時間
int name; //編組
boolean status; //狀態(tài)
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實(shí)現(xiàn)進(jìn)程間的互斥
if (name == mainclass.panel.islight) { //使用輔助變量實(shí)現(xiàn)進(jìn)程按順序循環(huán)
//System.out.println("now is: "+name);
change();
mainclass.panel.repaint();
try {
Thread.sleep(greentime);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.notifyAll(); //喚醒其他進(jìn)程
change();
mainclass.panel.LampChange();
mainclass.panel.repaint();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
try {
lock.wait(); //掛起進(jìn)程
} 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; //實(shí)現(xiàn)進(jìn)程循環(huán)的輔助變量
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); //創(chuàng)建并啟動線程
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 { //設(shè)置界面
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("南北左轉(zhuǎn)東西:");
lab2=new JLabel("東西直行:");
lab3=new JLabel("東西左轉(zhuǎn)南北:");
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, "請輸入完整數(shù)據(jù)!", "錯誤", 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("設(shè)置");
jmi1=new JMenuItem("開始模擬");
jmi1.addActionListener(this);
jmi2=new JMenuItem("退出模擬");
jmi2.addActionListener(this);
jmi3=new JMenuItem("隨機(jī)生成小車");
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, "請開始模擬再進(jìn)行設(shè)置", "錯誤", JOptionPane.INFORMATION_MESSAGE);
else new set();
}
}
public static void main(String[] args) {
new mainclass();
}
}
多線程正確性測試:
我們在lamp類的run()方法中添加了一句控制臺打印命令,每次進(jìn)程運(yùn)行時即會打印此進(jìn)程的name成員

正確的打印結(jié)果應(yīng)該為 0-1-2-3-4-0-1-2-3-4-.......-1-2-3-....
控制臺的輸出結(jié)果為:

符合預(yù)測結(jié)果,實(shí)驗(yàn)完成!
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java陷阱之a(chǎn)ssert關(guān)鍵字詳解
這篇文章詳細(xì)介紹了Java陷阱之a(chǎn)ssert關(guān)鍵字,有需要的朋友可以參考一下2013-09-09
SpringBoot Actuator潛在的OOM問題的解決
本文主要介紹了SpringBoot Actuator潛在的OOM問題的解決,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11
基于html5+java實(shí)現(xiàn)大文件上傳實(shí)例代碼
本文通過一段實(shí)例代碼給大家介紹基于html5+java實(shí)現(xiàn)大文件上傳,涉及到html5 java 文件上傳相關(guān)知識,感興趣的朋友一起學(xué)習(xí)吧2016-01-01
Spring項(xiàng)目里將SQL語句寫在.sql文件中的方法
這篇文章主要介紹了Spring項(xiàng)目里如何將SQL語句寫在.sql文件中的方法,文中給出了詳細(xì)的介紹和示例代碼,相信對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,有需要的朋友們下面來一起看看吧。2017-01-01
spring中@RestController和@Controller的區(qū)別小結(jié)
@RestController和@Controller這兩個注解用于創(chuàng)建Web應(yīng)用程序的控制器類,那么這兩個注解有哪些區(qū)別,本文就來介紹一下,并用示例代碼說明,感興趣的可以了解一下2023-09-09
Java泛型實(shí)現(xiàn)類型安全的通用類型轉(zhuǎn)換器
在開發(fā)中,我們常常需要在不同類型之間進(jìn)行轉(zhuǎn)換,為了提高代碼的可讀性與安全性,Java的泛型機(jī)制提供了強(qiáng)大的類型檢查能力,下面我們就來看看如何通過泛型實(shí)現(xiàn)類型安全的通用轉(zhuǎn)換器2024-11-11

