DispatcherThread--------------------------------------------------------------------------------
DispatcherThread继承了java.lang.Thread类,包含了两个成员:
protected DispatcherTask task; // 分派器任务实例
protected WorkerThreadPool pool; // 该实例关联的工作线程池,在该类的代码中没有使用
构造函数包含三个参数,ThreadGroup实例,线程名称,WorkerThreadPool实例,其中参数一和参数三都传入的是该DispatcherThread实例关联的工作线程池,前两个参数被用来构造父类Thread。查看JavaAPI,第一个参数指定本线程实例所属的线程组。
assign方法接收DispatcherTask task作为自己的task,然后通过start调用run方法:
synchronized (task) {
task.execute(); // 执行任务
task.notify(); // 唤醒正在等待该线程task的线程,也就是SpiderImpl实例,那里在为spiders和thinkers指定任务后就dispatchSpiderTask.wait()进入等待
}
WorkerThread--------------------------------------------------------------------------------
WorkerThread定义了三个状态常量,分别代表空闲、阻塞、工作,另外有一个变量代表本实例的状态。
WorkerThread的assigned和running表示是否分派了一个任务和是否应该继续运行,WorkerTask task表示被分派的任务。
stp变量代表了本实例所属的WorkerThreadPool。
WorkerThread的构造函数在初始化WorkerThreadPool时调用,里面传入了WorkerThreadPool stp, String name, int i三个参数,其中name和i代表线程池的线程名和在池中的序号,这两个参数被用来指定本线程实例的名称。
public synchronized void assign(WorkerTask task) 方法为本实例分配任务,对assigned和running进行判断,错误时抛出异常,然后设置任务和状态,做notify(),这里是唤醒run中进入的等待状态,以开始执行任务。这里涉及到成员的修改,所以加了synchronized防止并行操作。
public synchronized void run()在初始化结束后由WorkerThreadPool通过start方法调用。具体执行过程如下:
首先设定running状态;
然后抢占stp成员的锁,调用stp.notify()方法,唤醒在开启run方法后进入wait状态的WorkerThreadPool实例,这个等待唤醒过程保证了新建的顺序;
接下来进入running循环,没有分派任务时就进入wait状态,直到stopRunning或者assign方法时唤醒;
分派任务以后,调用task.prepare()进行准备,准备好后状态从阻塞变为工作,然后执行任务,关闭任务;
执行任务完毕以后,获取stp的锁,清空任务并修改状态,然后唤醒在stopRunning中等待的本实例和在stp.assign中等待的stp,以响应停止工作或者接收新的工作;
最后进入等待状态,直到停止工作或者分配新工作来唤醒。
public synchronized void stopRunning()方法停止本实例运行,如果分派了任务,则进入等待状态直到任务执行完毕唤醒,否则设置状态,并唤醒run方法去结束循环。
等待唤醒策略--------------------------------------------------------------------------------
1. 为了保证顺序执行,在调用子线程以后进入等待状态,等待子线程开始后唤醒,再去调用下一个子线程;
2. 在等待任务时,先进入等待状态,当分配任务后通过notify方法唤醒;
3. 运行状态作为循环条件控制线程是否结束;
4. 等待资源时进入等待状态,直到资源使用结束时唤醒。
下一步,分析DispatcherTask和WorkerTask代码。