知识点:
(1)Thread.sleep (new Random().nextInt(6)+1);暂停0-5之间的任意数
(2)List<String> vechicles=new ArrayList<String>();
Vechicles.add(“abc”);
System.out.println( Vechicles.remove(0));//移除此列表中指定位置上的索引为0的元素,同时向左移动所有后续元素(将其索引减 1)即移动第0个元素后,原第一个元素的索引就变成了0。remove返回的是”abc”,即集合中第0个元素,
(3)得到给定字符串所对应的枚举元素
例: enum Fruit
{
APPLE,BANANA,PEAR,ORANGE;
}
String fruit=”PEAR”;
Fruit f=Fruit.valueOf(fruit);//即得到了枚举Fruit的元素PEAR
(4)创建定时器
在5s以后,开始输出hello,之后每隔30s就输出一次
法一:
ScheduledExecutorService timer1=Executors.newScheduledThreadPool(1); /*或 ScheduledExecutorService timer1=
Executors.newSingleThreadScheduledExecutor(); timer1是接口ScheduledExecutorService的子类对象 */
Timer1.scheduleAtFixedRate(new Runnable(){/*此处的scheduleAtFixedRate()方法是接口timer1 对象所在的类实现的接口ScheduledExecutorService 中的方法*/
public void run() {
System.out.println(“hello”);
}},
5,
30,
TimeUnit.SECONDS);
Executors类中的方法
这是个工具类,里面的类都是静态的,工具类名一般以s结尾
public static ScheduledExecutorServicenewScheduledThreadPool(int PoolSize)
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
参数:
corePoolSize - 池中所保存的线程数,即使线程是空闲的也包括在内。
返回:
新创建的安排线程池 ,即接口 ScheduledExecutorService实现类的对象
抛出:
NullPointerException - 如果 threadFactory 为 null
public static ScheduledExecutorService newSingleThreadScheduledExecutor()
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。(注意,如果因为在关闭前的执行期间出现失败而终止了此单个线程,那么如果需要,一个新线程会代替它执行后续的任务)。可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。与其他等效的 newScheduledThreadPool(1) 不同,可保证无需重新配置此方法所返回的执行程序即可使用其他的线程。
返回:
新创建的安排执行程序,即实现接口 ScheduledExecutorService类的对象
public static ExecutorService newFixedThreadPool(int nThreads)
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。
参数:
nThreads - 池中的线程数
返回:
新创建的线程池
public static ExecutorService newSingleThreadExecutor()
创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。(注意,如果因为在关闭前的执行期间出现失败而终止了此单个线程,那么如果需要,一个新线程将代替它执行后续的任务)。可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。与其他等效的 newFixedThreadPool(1) 不同,可保证无需重新配置此方法所返回的执行程序即可使用其他的线程。
返回:
新创建的单线程 Executor
例子:创建一个线程,并执行线程中的run()中的代码
ExecutorService timer2=Executors.newSingleThreadExecutor();
/*或:
ExecutorService timer2=Executors.newFixedThreadPool(1);
此处的timer2是实现接口ExecutorService类的一个对象*/
timer.execute(new Runnable(){
/*此处的execute()是timer2所在的类实现的ExecutorService接口的父接口:Executor接口中的方法*/
public void run() {
System.out.println("hello world");
}});
等同于如下代码:
new Thread(new Runnable()
{
public void run()
{ System.out.println("hello world");}
}).start();
Executor接口中的方法:
void execute(Runnable command)
在未来某个时间执行给定的命令。该命令可能在新的线程、已入池的线程或者正调用的线程中执行,这由 Executor 实现决定。
参数:
command - 可运行的任务
ExecutorService接口
父接口是:Executor
ScheduledExecutorService接口
父接口是:ExecutorService
接口中的方法
ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit)
创建并执行在给定延迟后启用的一次性操作。
参数:
command - 要执行的任务
delay - 从现在开始延迟执行的时间
unit - 延迟参数的时间单位
返回:
表示挂起任务完成的 ScheduledFuture,并且其 get() 方法在完成后将返回 null
ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit)
创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在 initialDelay 后开始执行,然后在 initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推。如果任务的任何一个执行遇到异常,则后续执行都会被取消。否则,只能通过执行程序的取消或终止方法来终止该任务。如果此任务的任何一个执行要花费比其周期更长的时间,则将推迟后续执行,但不会同时执行。
参数:
command - 要执行的任务
initialDelay - 首次执行的延迟时间
period - 连续执行之间的周期
unit - initialDelay 和 period 参数的时间单位
返回:
表示挂起任务完成的 ScheduledFuture,并且其 get() 方法在取消后将抛出异常
抛出:
RejectedExecutionException - 如果无法安排执行该任务
NullPointerException - 如果 command 为 null
IllegalArgumentException - 如果 period 小于等于 0
上面的定时器代码用Timer、TimerTask类可改写成如下:
法二:
new Timer().schedule(new TimerTask()
{
public void run()
{ System.out.println("hello"); }
},
5000,
3000
);
TimerTask类中的方法
TimerTask类实现了Runnable接口,有run()方法
TimerTask类中的方法:
protected TimerTask()
创建一个新的计时器任务。
run()
{}
Timer类中的方法
public void schedule(TimerTask task,
long delay,
long period)
安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行。
在固定延迟执行中,根据前一次执行的实际执行时间来安排每次执行。如果由于任何原因(如垃圾回收或其他后台活动)而延迟了某次执行,则后续执行也将被延迟。从长期来看,执行的频率一般要稍慢于指定周期的倒数(假定Object.wait(long) 所依靠的系统时钟是准确的)。
固定延迟执行适用于那些需要“平稳”运行的重复活动。换句话说,它适用于在短期运行中保持频率准确要比在长期运行中更为重要的活动。这包括大多数动画任务,如以固定时间间隔闪烁的光标。这还包括为响应人类活动所执行的固定活动,如在按住键时自动重复输入字符。
参数:
task - 所要安排的任务。
delay - 执行任务前的延迟时间,单位是毫秒。
period - 执行各后续任务之间的时间间隔,单位是毫秒。
交通灯管理系统
模拟实现十字路口的交通灯管理系统逻辑,具体需求如下:
? 异步随机生成按照各个路线行驶的车辆。
例如:
由南向而来去往北向的车辆 ---- 直行车辆
由西向而来去往南向的车辆 ---- 右转车辆
由东向而来去往南向的车辆 ---- 左转车辆
。。。
? 信号灯忽略黄灯,只考虑红灯和绿灯。
? 应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
? 具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。
? 每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。
? 随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
? 不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
设计思路:
首先将交通图画出来如下所示:
根据图,我们可以看出总共有12条行车路线,分别是:
S2N,N2S,E2W,W2E,S2W,N2E,W2N,E2S,S2E,E2N,N2W,W2S
确定都需创建什么对象:
1、12条路线也就对应12条路线对象,在每条路线上,车源源不断的不定期的开来,如当前路线的灯为绿灯,则车每隔1秒开走1辆
2、12条路线就对应12个灯对象,当一个线路的灯绿时,它的相反方向的灯也变绿,当它变红的时候,下一个灯及它相反风向的灯就会变绿,这种依次变绿的过程,是按一定顺序的,所以可以用一个枚举来定义这12个灯,每个灯应对应3个参数,它的相反方向的灯,它的下一个灯,及它的红绿状态
3、这12个灯,需要一个控制器,控制将灯变绿,隔多长时间再把它变红,右转弯的四个灯是常绿,不需要控制,剩余的8个灯,只需要控制4个灯:S2N,S2W,W2E,W2N即可,它们相反方向的灯的红绿状态在同一时间和它们一样
4、最后需要创建一个调度类,创建控制器对象,让控制器开始控制灯红绿交换,并启动上面的12条路对象,让上面的车根据控制器所控制的当前路线灯红绿的状态,开始“走走“来来。
Road代码:
package test.traffic;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Road {
private String name=null;
List<String> vehicle=new ArrayList<String>();
public Road(String name)
{
this.name=name;
ExecutorService pool=Executors.newFixedThreadPool(1);
pool.execute(new Runnable()
{
int i=1;
@Override
public void run()
{
while(i<1000)
{
vehicle.add(Road.this.name+"路线上的第"+(i++)+"辆车");
try
{
Thread.sleep((new Random().nextInt(10)+1)*1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
// TODO Auto-generated method stub
}
}
});
pool.isShutdown();
ScheduledExecutorService timer= Executors.newSingleThreadScheduledExecutor();
timer.scheduleAtFixedRate(new Runnable()
{
@Override
public void run() {
boolean blue=Lamp.valueOf(Road.this.name).blue;
if(vehicle.size()!=0)
{ while(blue)
{
System.out.println(vehicle.remove(0)+"正在通过十字路口!");/*remove(0):移除此列表中指定位置上的索引为0的元素,同时向左移动所有后续元素(将其索引减 1)
即移动第0个元素后,原第一个元素的索引就变成了0。 */
}
// TODO Auto-generated method stub
} }
},
1,
2,
TimeUnit.SECONDS);
}}
Lamp(灯)代码:
package test.traffic;
enum Lamp
{ S2N("S2W",false,"N2S"),S2W("W2E",false,"N2E"),W2E("W2N",false,"E2W"),W2N("S2N",false,"E2S"),
N2S("null",false,"null"),N2E("null",false,"null"),E2W("null",false,"null"),E2S("null",false,"null"),
S2E(null,true,null),E2N(null,true,null),N2W(null,true,null),W2S(null,true,null);
public boolean blue=true;
String next=null;
String opposite=null;
private Lamp(String next,boolean blue,String opposite)
{
this.blue=blue;
this.next=next;
this.opposite=opposite;
};
public boolean isLighted()
{
return blue;
}
public void blueLight()
{ blue=true;
Lamp.valueOf(opposite).blue=true;
System.out.println(this.name()+"灯和"+Lamp.valueOf(opposite).name()+ "灯变绿了");
}
public Lamp redLight()
{
blue=false;
Lamp.valueOf(opposite).blue=false;
Lamp nextLamp=Lamp.valueOf(next);
nextLamp.blueLight();
return nextLamp;
}
}
LampController(灯得控制器)代码:
package test.traffic;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class LampController {
private Lamp currentLamp =Lamp.S2N;
public LampController()
{ System.out.println("最多有6个方向的车可以通过");
currentLamp.blueLight();
ScheduledExecutorService timer=Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(new Runnable()
{
@Override
public void run()
{
currentLamp=currentLamp.redLight();
}
},
10,
15,
TimeUnit.SECONDS);
}
}
启动代码:
package test.traffic;
public class Scheduler {
public static void main(String[] args) {
/*产生12个方向的路线*/
String [] directions = new String[]{
"S2N","S2W","E2W","E2S","N2S","N2E","W2E","W2N","S2E","E2N","N2W","W2S"
};
for(int i=0;i<directions.length;i++){
new Road(directions[i]);
}
/*产生整个交通灯系统*/
new LampController();
}
// TODO Auto-generated method stub
}